|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r81172 - in trunk: boost/thread boost/thread/detail boost/thread/pthread boost/thread/win32 libs/thread/src/pthread libs/thread/src/win32 libs/thread/test libs/thread/test/sync/futures/promise
From: vicente.botet_at_[hidden]
Date: 2012-11-04 11:47:04
Author: viboes
Date: 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
New Revision: 81172
URL: http://svn.boost.org/trac/boost/changeset/81172
Log:
Thread: Added promise::set_..._at_thread_exit
Added:
trunk/libs/thread/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp (contents, props changed)
trunk/libs/thread/test/sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp (contents, props changed)
trunk/libs/thread/test/sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp (contents, props changed)
trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp (contents, props changed)
trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp (contents, props changed)
Text files modified:
trunk/boost/thread/detail/config.hpp | 4
trunk/boost/thread/future.hpp | 434 ++++++++++++++++++++++++++++++++++++++-
trunk/boost/thread/lockable_traits.hpp | 208 ++++++++++--------
trunk/boost/thread/pthread/thread_data.hpp | 15 +
trunk/boost/thread/win32/thread_data.hpp | 12 +
trunk/libs/thread/src/pthread/thread.cpp | 40 +++
trunk/libs/thread/src/win32/thread.cpp | 64 +++--
trunk/libs/thread/test/Jamfile.v2 | 6
trunk/libs/thread/test/test_4882.cpp | 17 +
9 files changed, 656 insertions(+), 144 deletions(-)
Modified: trunk/boost/thread/detail/config.hpp
==============================================================================
--- trunk/boost/thread/detail/config.hpp (original)
+++ trunk/boost/thread/detail/config.hpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -73,8 +73,8 @@
// PROVIDE_PROMISE_LAZY
#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY \
- && ! defined BOOST_THREAD_PROMISE_LAZY
-#define BOOST_THREAD_PROMISE_LAZY
+ && ! defined BOOST_THREAD_PROVIDES_PROMISE_LAZY
+#define BOOST_THREAD_PROVIDES_PROMISE_LAZY
#endif
// PROVIDE_THREAD_EQ
Modified: trunk/boost/thread/future.hpp
==============================================================================
--- trunk/boost/thread/future.hpp (original)
+++ trunk/boost/thread/future.hpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -39,6 +39,7 @@
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <boost/scoped_array.hpp>
+#include <boost/enable_shared_from_this.hpp>
#include <boost/utility/enable_if.hpp>
#include <list>
#include <boost/next_prior.hpp>
@@ -257,11 +258,13 @@
relocker& operator=(relocker const&);
};
- struct future_object_base
+ struct future_object_base : enable_shared_from_this<future_object_base>
{
+
boost::exception_ptr exception;
bool done;
bool is_deferred;
+ bool is_constructed;
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
bool thread_was_interrupted;
#endif
@@ -276,7 +279,8 @@
future_object_base():
done(false),
- is_deferred(false)
+ is_deferred(false),
+ is_constructed(false)
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
, thread_was_interrupted(false)
#endif
@@ -334,6 +338,13 @@
}
do_continuation(lock);
}
+ void make_ready()
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ boost::unique_lock<boost::mutex> lock(mutex);
+ mark_finished_internal(lock);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ }
void do_callback(boost::unique_lock<boost::mutex>& lock)
{
@@ -348,17 +359,24 @@
void wait_internal(boost::unique_lock<boost::mutex> &lock, bool rethrow=true)
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
do_callback(lock);
- //if (!done)
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ //if (!done) // fixme why this doesn't works?
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
if (is_deferred)
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
is_deferred=false;
execute(lock);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+
//lock.unlock();
}
else
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
while(!done)
{
waiters.wait(lock);
@@ -366,11 +384,14 @@
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
if(rethrow && thread_was_interrupted)
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
throw boost::thread_interrupted();
}
#endif
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
if(rethrow && exception)
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
boost::rethrow_exception(exception);
}
}
@@ -378,8 +399,11 @@
}
void wait(bool rethrow=true)
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
boost::unique_lock<boost::mutex> lock(mutex);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
wait_internal(lock, rethrow);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
}
#if defined BOOST_THREAD_USES_DATETIME
@@ -424,13 +448,19 @@
#endif
void mark_exceptional_finish_internal(boost::exception_ptr const& e, boost::unique_lock<boost::mutex>& lock)
{
+ //std::cout << "**************"<<__FILE__ << ":" << __LINE__ <<std::endl;
exception=e;
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
mark_finished_internal(lock);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
}
void mark_exceptional_finish()
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
boost::unique_lock<boost::mutex> lock(mutex);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
mark_exceptional_finish_internal(boost::current_exception(), lock);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
void mark_interrupted_finish()
@@ -440,8 +470,25 @@
mark_finished_internal(lock);
}
#endif
+ void set_exception_at_thread_exit(exception_ptr e)
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ unique_lock<boost::mutex> lk(mutex);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ if (has_value(lk))
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ throw_exception(promise_already_satisfied());
+ }
+ //std::cout << "**************"<<__FILE__ << ":" << __LINE__ <<std::endl;
+ exception=e;
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ }
bool has_value()
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
boost::lock_guard<boost::mutex> lock(mutex);
return done && !(exception
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
@@ -449,6 +496,15 @@
#endif
);
}
+ bool has_value(unique_lock<boost::mutex>& )
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ return done && !(exception
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ || thread_was_interrupted
+#endif
+ );
+ }
bool has_exception()
{
boost::lock_guard<boost::mutex> lock(mutex);
@@ -458,6 +514,14 @@
#endif
);
}
+ bool has_exception(unique_lock<boost::mutex>&)
+ {
+ return done && (exception
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ || thread_was_interrupted
+#endif
+ );
+ }
template<typename F,typename U>
void set_wait_callback(F f,U* u)
@@ -596,7 +660,9 @@
move_dest_type get()
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
wait();
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
return static_cast<move_dest_type>(*result);
//return boost::move(*result); // todo check why this doesn't works (references?)
}
@@ -621,6 +687,138 @@
}
}
+
+ //void set_value_at_thread_exit(source_reference_type result_)
+ void set_value_at_thread_exit(const T & result_)
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ unique_lock<boost::mutex> lk(this->mutex);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ if (this->has_value(lk))
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ throw_exception(promise_already_satisfied());
+ }
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ future_traits<T>::init(result,result_);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ this->is_constructed = true;
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ }
+ //void set_value_at_thread_exit(rvalue_source_type result_)
+ void set_value_at_thread_exit(BOOST_THREAD_RV_REF(T) result_)
+ {
+ unique_lock<boost::mutex> lk(this->mutex);
+ if (this->has_value(lk))
+ throw_exception(promise_already_satisfied());
+ future_traits<T>::init(result,static_cast<rvalue_source_type>(result_));
+ this->is_constructed = true;
+ get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
+ }
+
+
+ private:
+ future_object(future_object const&);
+ future_object& operator=(future_object const&);
+ };
+
+ template<typename T>
+ struct future_object<T&>:
+ detail::future_object_base
+ {
+ typedef typename future_traits<T>::storage_type storage_type;
+ typedef typename future_traits<T>::source_reference_type source_reference_type;
+ typedef typename future_traits<T>::rvalue_source_type rvalue_source_type;
+ typedef typename future_traits<T>::move_dest_type move_dest_type;
+ typedef typename future_traits<T>::shared_future_get_result_type shared_future_get_result_type;
+
+ T* result;
+
+ future_object():
+ result(0)
+ {}
+
+ ~future_object()
+ {
+ }
+
+ void mark_finished_with_result_internal(T& result_, boost::unique_lock<boost::mutex>& lock)
+ {
+ //future_traits<T>::init(result,result_);
+ result= &result_;
+ mark_finished_internal(lock);
+ }
+
+// void mark_finished_with_result_internal(rvalue_source_type result_, boost::unique_lock<boost::mutex>& lock)
+// {
+// future_traits<T>::init(result,static_cast<rvalue_source_type>(result_));
+// mark_finished_internal(lock);
+// }
+
+ void mark_finished_with_result(T& result_)
+ {
+ boost::unique_lock<boost::mutex> lock(mutex);
+ mark_finished_with_result_internal(result_, lock);
+ }
+
+// void mark_finished_with_result(rvalue_source_type result_)
+// {
+// boost::unique_lock<boost::mutex> lock(mutex);
+// mark_finished_with_result_internal(static_cast<rvalue_source_type>(result_), lock);
+// }
+
+
+ T& get()
+ {
+ wait();
+ //return static_cast<T&>(*result);
+ return *result;
+ }
+
+ T& get_sh()
+ {
+ wait();
+ //return static_cast<shared_future_get_result_type>(*result);
+ return *result;
+ }
+
+ // todo move this to detail::future_object_base
+ future_state::state get_state()
+ {
+ boost::lock_guard<boost::mutex> guard(mutex);
+ if(!done)
+ {
+ return future_state::waiting;
+ }
+ else
+ {
+ return future_state::ready;
+ }
+ }
+
+ void set_value_at_thread_exit(T& result_)
+ {
+ unique_lock<boost::mutex> lk(this->mutex);
+ if (this->has_value(lk))
+ throw_exception(promise_already_satisfied());
+ //future_traits<T>::init(result,result_);
+ result= &result_;
+ this->is_constructed = true;
+ get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
+ }
+// void set_value_at_thread_exit(rvalue_source_type result_)
+// {
+// unique_lock<boost::mutex> lk(this->mutex);
+// if (this->has_value())
+// throw_exception(promise_already_satisfied());
+// future_traits<T>::init(result,static_cast<rvalue_source_type>(result_));
+// this->is_constructed = true;
+// get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
+// }
+
+
private:
future_object(future_object const&);
future_object& operator=(future_object const&);
@@ -648,7 +846,9 @@
void get()
{
- wait();
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ this->wait();
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
}
void get_sh()
{
@@ -667,6 +867,22 @@
return future_state::ready;
}
}
+ void set_value_at_thread_exit()
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ unique_lock<boost::mutex> lk(this->mutex);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ if (this->has_value(lk))
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ throw_exception(promise_already_satisfied());
+ }
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ this->is_constructed = true;
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ }
private:
future_object(future_object const&);
future_object& operator=(future_object const&);
@@ -1275,15 +1491,22 @@
// retrieving the value
move_dest_type get()
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
if(!this->future_)
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
boost::throw_exception(future_uninitialized());
}
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
future_ptr fut_=this->future_;
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
this->future_.reset();
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
return fut_->get();
#else
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
return this->future_->get();
#endif
}
@@ -1408,7 +1631,7 @@
void lazy_init()
{
-#if defined BOOST_THREAD_PROMISE_LAZY
+#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY
if(!atomic_load(&future_))
{
future_ptr blank;
@@ -1432,7 +1655,7 @@
}
#endif
promise():
-#if defined BOOST_THREAD_PROMISE_LAZY
+#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY
future_(),
#else
future_(new detail::future_object<R>()),
@@ -1526,9 +1749,31 @@
}
// setting the result with deferred notification
- //void set_value_at_thread_exit(const R& r); // NOT YET IMPLEMENTED
- //void set_value_at_thread_exit(see below); // NOT YET IMPLEMENTED
- //void set_exception_at_thread_exit(exception_ptr p); // NOT YET IMPLEMENTED
+ void set_value_at_thread_exit(const R& r)
+ {
+ if (future_.get()==0)
+ {
+ boost::throw_exception(promise_moved());
+ }
+ future_->set_value_at_thread_exit(r);
+ }
+
+ void set_value_at_thread_exit(BOOST_THREAD_RV_REF(R) r)
+ {
+ if (future_.get()==0)
+ {
+ boost::throw_exception(promise_moved());
+ }
+ future_->set_value_at_thread_exit(boost::move(r));
+ }
+ void set_exception_at_thread_exit(exception_ptr e)
+ {
+ if (future_.get()==0)
+ {
+ boost::throw_exception(promise_moved());
+ }
+ future_->set_exception_at_thread_exit(e);
+ }
template<typename F>
void set_wait_callback(F f)
@@ -1539,6 +1784,148 @@
};
+ template <typename R>
+ class promise<R&>
+ {
+ typedef boost::shared_ptr<detail::future_object<R&> > future_ptr;
+
+ future_ptr future_;
+ bool future_obtained;
+
+ void lazy_init()
+ {
+#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY
+ if(!atomic_load(&future_))
+ {
+ future_ptr blank;
+ atomic_compare_exchange(&future_,&blank,future_ptr(new detail::future_object<R&>));
+ }
+#endif
+ }
+
+ public:
+ BOOST_THREAD_MOVABLE_ONLY(promise)
+#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS
+ template <class Allocator>
+ promise(boost::allocator_arg_t, Allocator a)
+ {
+ typedef typename Allocator::template rebind<detail::future_object<R&> >::other A2;
+ A2 a2(a);
+ typedef thread_detail::allocator_destructor<A2> D;
+
+ future_ = future_ptr(::new(a2.allocate(1)) detail::future_object<R&>(), D(a2, 1) );
+ future_obtained = false;
+ }
+#endif
+ promise():
+#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY
+ future_(),
+#else
+ future_(new detail::future_object<R&>()),
+#endif
+ future_obtained(false)
+ {}
+
+ ~promise()
+ {
+ if(future_)
+ {
+ boost::unique_lock<boost::mutex> lock(future_->mutex);
+
+ if(!future_->done)
+ {
+ future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock);
+ }
+ }
+ }
+
+ // Assignment
+ promise(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT :
+ future_(BOOST_THREAD_RV(rhs).future_),future_obtained(BOOST_THREAD_RV(rhs).future_obtained)
+ {
+ BOOST_THREAD_RV(rhs).future_.reset();
+ BOOST_THREAD_RV(rhs).future_obtained=false;
+ }
+ promise & operator=(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT
+ {
+ future_=BOOST_THREAD_RV(rhs).future_;
+ future_obtained=BOOST_THREAD_RV(rhs).future_obtained;
+ BOOST_THREAD_RV(rhs).future_.reset();
+ BOOST_THREAD_RV(rhs).future_obtained=false;
+ return *this;
+ }
+
+ void swap(promise& other)
+ {
+ future_.swap(other.future_);
+ std::swap(future_obtained,other.future_obtained);
+ }
+
+ // Result retrieval
+ BOOST_THREAD_FUTURE<R&> get_future()
+ {
+ lazy_init();
+ if (future_.get()==0)
+ {
+ boost::throw_exception(promise_moved());
+ }
+ if (future_obtained)
+ {
+ boost::throw_exception(future_already_retrieved());
+ }
+ future_obtained=true;
+ return BOOST_THREAD_FUTURE<R&>(future_);
+ }
+
+ void set_value(R& r)
+ {
+ lazy_init();
+ boost::unique_lock<boost::mutex> lock(future_->mutex);
+ if(future_->done)
+ {
+ boost::throw_exception(promise_already_satisfied());
+ }
+ future_->mark_finished_with_result_internal(r, lock);
+ }
+
+ void set_exception(boost::exception_ptr p)
+ {
+ lazy_init();
+ boost::unique_lock<boost::mutex> lock(future_->mutex);
+ if(future_->done)
+ {
+ boost::throw_exception(promise_already_satisfied());
+ }
+ future_->mark_exceptional_finish_internal(p, lock);
+ }
+
+ // setting the result with deferred notification
+ void set_value_at_thread_exit(R& r)
+ {
+ if (future_.get()==0)
+ {
+ boost::throw_exception(promise_moved());
+ }
+ future_->set_value_at_thread_exit(r);
+ }
+
+ void set_exception_at_thread_exit(exception_ptr e)
+ {
+ if (future_.get()==0)
+ {
+ boost::throw_exception(promise_moved());
+ }
+ future_->set_exception_at_thread_exit(e);
+ }
+
+ template<typename F>
+ void set_wait_callback(F f)
+ {
+ lazy_init();
+ future_->set_wait_callback(f,this);
+ }
+
+ };
template <>
class promise<void>
{
@@ -1549,7 +1936,7 @@
void lazy_init()
{
-#if defined BOOST_THREAD_PROMISE_LAZY
+#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY
if(!atomic_load(&future_))
{
future_ptr blank;
@@ -1573,7 +1960,7 @@
}
#endif
promise():
-#if defined BOOST_THREAD_PROMISE_LAZY
+#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY
future_(),
#else
future_(new detail::future_object<void>),
@@ -1657,6 +2044,31 @@
future_->mark_exceptional_finish_internal(p,lock);
}
+ // setting the result with deferred notification
+ void set_value_at_thread_exit()
+ {
+
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+
+ if (future_.get()==0)
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ boost::throw_exception(promise_moved());
+ }
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ future_->set_value_at_thread_exit();
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ }
+
+ void set_exception_at_thread_exit(exception_ptr e)
+ {
+ if (future_.get()==0)
+ {
+ boost::throw_exception(promise_moved());
+ }
+ future_->set_exception_at_thread_exit(e);
+ }
+
template<typename F>
void set_wait_callback(F f)
{
Modified: trunk/boost/thread/lockable_traits.hpp
==============================================================================
--- trunk/boost/thread/lockable_traits.hpp (original)
+++ trunk/boost/thread/lockable_traits.hpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -8,26 +8,17 @@
#define BOOST_THREAD_LOCKABLE_TRAITS_HPP
#include <boost/thread/detail/config.hpp>
-#include <boost/thread/detail/move.hpp>
-#include <boost/thread/exceptions.hpp>
-//#include <boost/thread/testable_mutex.hpp>
-#include <boost/thread/thread_time.hpp>
#include <boost/assert.hpp>
-#ifdef BOOST_THREAD_USES_CHRONO
-#include <boost/chrono/time_point.hpp>
-#include <boost/chrono/duration.hpp>
-#endif
#include <boost/detail/workaround.hpp>
#include <boost/type_traits/is_class.hpp>
-#include <algorithm>
-#include <iterator>
-
#include <boost/config/abi_prefix.hpp>
namespace boost
{
+ namespace sync
+ {
#if defined(BOOST_NO_SFINAE) || \
BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \
@@ -72,101 +63,130 @@
bool, value=sizeof(has_member<derived>(0))==sizeof(true_type)); \
}
- BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(lock);
- BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(unlock);
- BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(try_lock);
-
- template<typename T,bool=has_member_called_lock<T>::value >
- struct has_member_lock
- {
- BOOST_STATIC_CONSTANT(bool, value=false);
- };
-
- template<typename T>
- struct has_member_lock<T,true>
- {
- typedef char true_type;
- struct false_type
- {
- true_type dummy[2];
- };
-
- template<typename U,typename V>
- static true_type has_member(V (U::*)());
- template<typename U>
- static false_type has_member(U);
-
- BOOST_STATIC_CONSTANT(
- bool,value=sizeof(has_member_lock<T>::has_member(&T::lock))==sizeof(true_type));
- };
-
- template<typename T,bool=has_member_called_unlock<T>::value >
- struct has_member_unlock
- {
- BOOST_STATIC_CONSTANT(bool, value=false);
- };
-
- template<typename T>
- struct has_member_unlock<T,true>
- {
- typedef char true_type;
- struct false_type
- {
- true_type dummy[2];
- };
-
- template<typename U,typename V>
- static true_type has_member(V (U::*)());
- template<typename U>
- static false_type has_member(U);
-
- BOOST_STATIC_CONSTANT(
- bool,value=sizeof(has_member_unlock<T>::has_member(&T::unlock))==sizeof(true_type));
- };
-
- template<typename T,bool=has_member_called_try_lock<T>::value >
- struct has_member_try_lock
- {
- BOOST_STATIC_CONSTANT(bool, value=false);
- };
-
- template<typename T>
- struct has_member_try_lock<T,true>
- {
- typedef char true_type;
- struct false_type
- {
- true_type dummy[2];
- };
-
- template<typename U>
- static true_type has_member(bool (U::*)());
- template<typename U>
- static false_type has_member(U);
-
- BOOST_STATIC_CONSTANT(
- bool,value=sizeof(has_member_try_lock<T>::has_member(&T::try_lock))==sizeof(true_type));
- };
+ BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(lock)
+; BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(unlock);
+ BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(try_lock);
+
+ template<typename T,bool=has_member_called_lock<T>::value >
+ struct has_member_lock
+ {
+ BOOST_STATIC_CONSTANT(bool, value=false);
+ };
+
+ template<typename T>
+ struct has_member_lock<T,true>
+ {
+ typedef char true_type;
+ struct false_type
+ {
+ true_type dummy[2];
+ };
+
+ template<typename U,typename V>
+ static true_type has_member(V (U::*)());
+ template<typename U>
+ static false_type has_member(U);
+
+ BOOST_STATIC_CONSTANT(
+ bool,value=sizeof(has_member_lock<T>::has_member(&T::lock))==sizeof(true_type));
+ };
+
+ template<typename T,bool=has_member_called_unlock<T>::value >
+ struct has_member_unlock
+ {
+ BOOST_STATIC_CONSTANT(bool, value=false);
+ };
+
+ template<typename T>
+ struct has_member_unlock<T,true>
+ {
+ typedef char true_type;
+ struct false_type
+ {
+ true_type dummy[2];
+ };
+
+ template<typename U,typename V>
+ static true_type has_member(V (U::*)());
+ template<typename U>
+ static false_type has_member(U);
+
+ BOOST_STATIC_CONSTANT(
+ bool,value=sizeof(has_member_unlock<T>::has_member(&T::unlock))==sizeof(true_type));
+ };
+
+ template<typename T,bool=has_member_called_try_lock<T>::value >
+ struct has_member_try_lock
+ {
+ BOOST_STATIC_CONSTANT(bool, value=false);
+ };
+
+ template<typename T>
+ struct has_member_try_lock<T,true>
+ {
+ typedef char true_type;
+ struct false_type
+ {
+ true_type dummy[2];
+ };
+
+ template<typename U>
+ static true_type has_member(bool (U::*)());
+ template<typename U>
+ static false_type has_member(U);
+
+ BOOST_STATIC_CONSTANT(
+ bool,value=sizeof(has_member_try_lock<T>::has_member(&T::try_lock))==sizeof(true_type));
+ };
}
-
template<typename T>
- struct is_mutex_type
+ struct is_basic_lockable
{
- BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock<T>::value &&
- detail::has_member_unlock<T>::value &&
- detail::has_member_try_lock<T>::value);
-
+ BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock<T>::value &&
+ detail::has_member_unlock<T>::value);
};
+ template<typename T>
+ struct is_lockable
+ {
+ BOOST_STATIC_CONSTANT(bool, value =
+ is_basic_lockable<T>::value &&
+ detail::has_member_try_lock<T>::value);
+ };
+
#else
template<typename T>
- struct is_mutex_type
+ struct is_basic_lockable
+ {
+ BOOST_STATIC_CONSTANT(bool, value = false);
+ };
+ template<typename T>
+ struct is_lockable
{
- BOOST_STATIC_CONSTANT(bool, value = false);
+ BOOST_STATIC_CONSTANT(bool, value = false);
};
#endif
+ template<typename T>
+ struct is_recursive_mutex_sur_parolle
+ {
+ BOOST_STATIC_CONSTANT(bool, value = false);
+ };
+
+ template<typename T>
+ struct is_recursive_basic_lockable
+ {
+ BOOST_STATIC_CONSTANT(bool, value = is_basic_lockable<T>::value &&
+ is_recursive_mutex_sur_parolle<T>::value);
+ };
+ }
+ template<typename T>
+ struct is_mutex_type
+ {
+ BOOST_STATIC_CONSTANT(bool, value = sync::is_lockable<T>::value);
+ };
+
}
#include <boost/config/abi_suffix.hpp>
Modified: trunk/boost/thread/pthread/thread_data.hpp
==============================================================================
--- trunk/boost/thread/pthread/thread_data.hpp (original)
+++ trunk/boost/thread/pthread/thread_data.hpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -78,6 +78,7 @@
namespace detail
{
+ struct future_object_base;
struct tss_cleanup_function;
struct thread_exit_callback_node;
struct tss_data_node
@@ -119,6 +120,9 @@
> notify_list_t;
notify_list_t notify;
+ typedef std::vector<shared_ptr<future_object_base> > async_states_t;
+ async_states_t async_states_;
+
thread_data_base():
done(false),join_started(false),joined(false),
thread_exit_callbacks(0),
@@ -127,7 +131,8 @@
interrupt_requested(false),
#endif
current_cond(0),
- notify()
+ notify(),
+ async_states_()
{}
virtual ~thread_data_base();
@@ -138,6 +143,14 @@
{
notify.push_back(std::pair<condition_variable*, mutex*>(cv, m));
}
+
+ void make_ready_at_thread_exit(shared_ptr<future_object_base> as)
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ async_states_.push_back(as);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ }
+
};
BOOST_THREAD_DECL thread_data_base* get_current_thread_data();
Modified: trunk/boost/thread/win32/thread_data.hpp
==============================================================================
--- trunk/boost/thread/win32/thread_data.hpp (original)
+++ trunk/boost/thread/win32/thread_data.hpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -72,6 +72,7 @@
namespace detail
{
+ struct future_object_base;
struct tss_cleanup_function;
struct thread_exit_callback_node;
struct tss_data_node
@@ -107,6 +108,8 @@
> notify_list_t;
notify_list_t notify;
+ typedef std::vector<shared_ptr<future_object_base> > async_states_t;
+ async_states_t async_states_;
thread_data_base():
count(0),thread_handle(detail::win32::invalid_handle_value),
@@ -118,7 +121,8 @@
interruption_enabled(true),
#endif
id(0),
- notify()
+ notify(),
+ async_states_()
{}
virtual ~thread_data_base();
@@ -150,7 +154,13 @@
notify.push_back(std::pair<condition_variable*, mutex*>(cv, m));
}
+ void make_ready_at_thread_exit(shared_ptr<future_object_base> as)
+ {
+ async_states_.push_back(as);
+ }
+
};
+ BOOST_THREAD_DECL thread_data_base* get_current_thread_data();
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
Modified: trunk/libs/thread/src/pthread/thread.cpp
==============================================================================
--- trunk/libs/thread/src/pthread/thread.cpp (original)
+++ trunk/libs/thread/src/pthread/thread.cpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -16,6 +16,7 @@
#include <boost/thread/once.hpp>
#include <boost/thread/tss.hpp>
#include <boost/throw_exception.hpp>
+#include <boost/thread/future.hpp>
#ifdef __GLIBC__
#include <sys/sysinfo.h>
@@ -34,14 +35,22 @@
{
thread_data_base::~thread_data_base()
{
- {
for (notify_list_t::iterator i = notify.begin(), e = notify.end();
i != e; ++i)
{
i->second->unlock();
i->first->notify_all();
}
- }
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end();
+ i != e; ++i)
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ (*i)->make_ready();
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ }
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+
}
struct thread_exit_callback_node
@@ -68,11 +77,16 @@
{
static void tls_destructor(void* data)
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
if(thread_info)
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks)
{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+
while(thread_info->thread_exit_callbacks)
{
detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
@@ -98,8 +112,17 @@
thread_info->tss_data.erase(current);
}
}
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ if (thread_info) {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
thread_info->self.reset();
+ } else{
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+
+ }
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
}
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
}
}
@@ -162,10 +185,13 @@
}
// Removed as it stops the debugger identifying the cause of the exception
// Unhandled exceptions still cause the application to terminate
-// BOOST_CATCH(...)
-// {
-// std::terminate();
-// }
+ BOOST_CATCH(...)
+ {
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+ throw;
+
+ std::terminate();
+ }
BOOST_CATCH_END
#endif
detail::tls_destructor(thread_info.get());
@@ -173,6 +199,8 @@
boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
thread_info->done=true;
thread_info->done_condition.notify_all();
+ //std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+
return 0;
}
}
Modified: trunk/libs/thread/src/win32/thread.cpp
==============================================================================
--- trunk/libs/thread/src/win32/thread.cpp (original)
+++ trunk/libs/thread/src/win32/thread.cpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -18,6 +18,7 @@
#include <boost/thread/tss.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/detail/tss_hooks.hpp>
+#include <boost/thread/future.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
@@ -37,16 +38,20 @@
{
thread_data_base::~thread_data_base()
{
- {
for (notify_list_t::iterator i = notify.begin(), e = notify.end();
i != e; ++i)
{
i->second->unlock();
i->first->notify_all();
}
- }
+ for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end();
+ i != e; ++i)
+ {
+ (*i)->make_ready();
+ }
}
}
+
namespace
{
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
@@ -76,15 +81,6 @@
}
}
- detail::thread_data_base* get_current_thread_data()
- {
- if(current_thread_tls_key==TLS_OUT_OF_INDEXES)
- {
- return 0;
- }
- return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
- }
-
void set_current_thread_data(detail::thread_data_base* new_data)
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
@@ -99,6 +95,20 @@
}
}
+ }
+ namespace detail
+ {
+ thread_data_base* get_current_thread_data()
+ {
+ if(current_thread_tls_key==TLS_OUT_OF_INDEXES)
+ {
+ return 0;
+ }
+ return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
+ }
+ }
+ namespace
+ {
#ifndef BOOST_HAS_THREADEX
// Windows CE doesn't define _beginthreadex
@@ -157,7 +167,7 @@
{
void run_thread_exit_callbacks()
{
- detail::thread_data_ptr current_thread_data(get_current_thread_data(),false);
+ detail::thread_data_ptr current_thread_data(detail::get_current_thread_data(),false);
if(current_thread_data)
{
while(! current_thread_data->tss_data.empty() || current_thread_data->thread_exit_callbacks)
@@ -295,11 +305,11 @@
detail::thread_data_base* get_or_make_current_thread_data()
{
- detail::thread_data_base* current_thread_data(get_current_thread_data());
+ detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
if(!current_thread_data)
{
make_external_thread_data();
- current_thread_data=get_current_thread_data();
+ current_thread_data=detail::get_current_thread_data();
}
return current_thread_data;
}
@@ -487,10 +497,10 @@
handles[handle_count++]=handle_to_wait_for;
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- if(get_current_thread_data() && get_current_thread_data()->interruption_enabled)
+ if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled)
{
interruption_index=handle_count;
- handles[handle_count++]=get_current_thread_data()->interruption_handle;
+ handles[handle_count++]=detail::get_current_thread_data()->interruption_handle;
}
#endif
detail::win32::handle_manager timer_handle;
@@ -547,7 +557,7 @@
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
else if(notified_index==interruption_index)
{
- detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
+ detail::win32::ResetEvent(detail::get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
#endif
@@ -584,19 +594,19 @@
{
if(interruption_enabled() && interruption_requested())
{
- detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
+ detail::win32::ResetEvent(detail::get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
}
bool interruption_enabled() BOOST_NOEXCEPT
{
- return get_current_thread_data() && get_current_thread_data()->interruption_enabled;
+ return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled;
}
bool interruption_requested() BOOST_NOEXCEPT
{
- return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0);
+ return detail::get_current_thread_data() && (detail::win32::WaitForSingleObject(detail::get_current_thread_data()->interruption_handle,0)==0);
}
#endif
@@ -611,15 +621,15 @@
{
if(interruption_was_enabled)
{
- get_current_thread_data()->interruption_enabled=false;
+ detail::get_current_thread_data()->interruption_enabled=false;
}
}
disable_interruption::~disable_interruption() BOOST_NOEXCEPT
{
- if(get_current_thread_data())
+ if(detail::get_current_thread_data())
{
- get_current_thread_data()->interruption_enabled=interruption_was_enabled;
+ detail::get_current_thread_data()->interruption_enabled=interruption_was_enabled;
}
}
@@ -627,15 +637,15 @@
{
if(d.interruption_was_enabled)
{
- get_current_thread_data()->interruption_enabled=true;
+ detail::get_current_thread_data()->interruption_enabled=true;
}
}
restore_interruption::~restore_interruption() BOOST_NOEXCEPT
{
- if(get_current_thread_data())
+ if(detail::get_current_thread_data())
{
- get_current_thread_data()->interruption_enabled=false;
+ detail::get_current_thread_data()->interruption_enabled=false;
}
}
}
@@ -734,7 +744,7 @@
BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
{
- detail::thread_data_base* const current_thread_data(get_current_thread_data());
+ detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
if(current_thread_data)
{
current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
Modified: trunk/libs/thread/test/Jamfile.v2
==============================================================================
--- trunk/libs/thread/test/Jamfile.v2 (original)
+++ trunk/libs/thread/test/Jamfile.v2 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -267,6 +267,11 @@
[ thread-run2 ./sync/futures/promise/set_value_const_pass.cpp : promise__set_value_const_p ]
[ thread-run2 ./sync/futures/promise/set_value_void_pass.cpp : promise__set_value_void_p ]
[ thread-run2 ./sync/futures/promise/use_allocator_pass.cpp : promise__use_allocator_p ]
+ [ thread-run2 ./sync/futures/promise/set_exception_at_thread_exit_pass.cpp : promise__set_exception_at_thread_exit_p ]
+ [ thread-run2 ./sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp : promise__set_lvalue_at_thread_exit_p ]
+ [ thread-run2 ./sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp : promise__set_rvalue_at_thread_exit_p ]
+ [ thread-run2 ./sync/futures/promise/set_value_at_thread_exit_const_pass.cpp : promise__set_value_at_thread_exit_const_p ]
+ [ thread-run2 ./sync/futures/promise/set_value_at_thread_exit_void_pass.cpp : promise__set_value_at_thread_exit_void_p ]
;
#explicit ts_future ;
@@ -582,6 +587,7 @@
explicit ts_ ;
test-suite ts_
:
+
#[ thread-run ../example/unwrap.cpp ]
;
Added: trunk/libs/thread/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Copyright (C) 2011 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// <boost/thread/future.hpp>
+
+// class promise<R>
+
+// void promise::set_exception_at_thread_exit(exception_ptr p);
+
+#define BOOST_THREAD_VERSION 4
+
+#include <boost/thread/future.hpp>
+#include <boost/detail/lightweight_test.hpp>
+#include <boost/static_assert.hpp>
+
+namespace boost
+{
+ template <typename T>
+ struct wrap
+ {
+ wrap(T const& v) :
+ value(v)
+ {
+ }
+ T value;
+
+ };
+
+ template <typename T>
+ exception_ptr make_exception_ptr(T v)
+ {
+ return copy_exception(wrap<T> (v));
+ }
+}
+
+//void func(boost::promise<int> p)
+boost::promise<int> p;
+void func()
+{
+ p.set_exception_at_thread_exit(boost::make_exception_ptr(3));
+}
+
+int main()
+{
+ {
+ typedef int T;
+ //boost::promise<T> p;
+ boost::future<T> f = p.get_future();
+ //boost::thread(func, boost::move(p)).detach();
+ boost::thread(func).detach();
+ try
+ {
+ f.get();
+ BOOST_TEST(false);
+ }
+ catch (boost::wrap<int> i)
+ {
+ BOOST_TEST(i.value == 3);
+ }
+ catch (...)
+ {
+ BOOST_TEST(false);
+ }
+ }
+ return boost::report_errors();
+}
+
Added: trunk/libs/thread/test/sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/test/sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Copyright (C) 2011 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// <boost/thread/future.hpp>
+
+// class promise<R>
+
+// void promise<R&>::set_value_at_thread_exit(R& r);
+
+#define BOOST_THREAD_VERSION 4
+
+#include <boost/thread/future.hpp>
+#include <boost/detail/lightweight_test.hpp>
+#include <memory>
+
+int i = 0;
+
+//void func(boost::promise<int&> p)
+boost::promise<int&> p;
+void func()
+{
+ p.set_value_at_thread_exit(i);
+ i = 4;
+}
+
+int main()
+{
+ {
+ //boost::promise<int&> p;
+ boost::future<int&> f = p.get_future();
+ //boost::thread(func, boost::move(p)).detach();
+ boost::thread(func).detach();
+ int r = f.get();
+ BOOST_TEST(r == 4);
+ }
+ return boost::report_errors();
+}
+
Added: trunk/libs/thread/test/sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/test/sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Copyright (C) 2011 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// <boost/thread/future.hpp>
+
+// class promise<R>
+
+// void promise::set_exception_at_thread_exit(exception_ptr p);
+
+#define BOOST_THREAD_VERSION 3
+
+#include <boost/thread/future.hpp>
+#include <boost/detail/lightweight_test.hpp>
+#include <boost/thread/detail/memory.hpp>
+#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
+
+//void func(boost::promise<boost::interprocess::unique_ptr<int, boost::default_delete<int> > > p)
+boost::promise<boost::interprocess::unique_ptr<int, boost::default_delete<int> > > p;
+void func()
+{
+ boost::interprocess::unique_ptr<int, boost::default_delete<int> > uptr(new int(5));
+ p.set_value_at_thread_exit(boost::move(uptr));
+}
+
+int main()
+{
+ {
+ //boost::promise<boost::interprocess::unique_ptr<int, boost::default_delete<int>> > p;
+ boost::future<boost::interprocess::unique_ptr<int, boost::default_delete<int> > > f = p.get_future();
+ //boost::thread(func, boost::move(p)).detach();
+ boost::thread(func).detach();
+ BOOST_TEST(*f.get() == 5);
+ }
+
+ return boost::report_errors();
+}
+
Added: trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Copyright (C) 2011 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// <boost/thread/future.hpp>
+
+// class promise<R>
+
+// void promise::set_value_at_thread_exit(const R& r);
+
+#define BOOST_THREAD_VERSION 4
+
+#include <boost/thread/future.hpp>
+#include <boost/detail/lightweight_test.hpp>
+
+boost::promise<int> p;
+//void func(boost::promise<int> p)
+void func()
+{
+ const int i = 5;
+ p.set_value_at_thread_exit(i);
+}
+
+int main()
+{
+ {
+ //boost::promise<int> p;
+ boost::future<int> f = p.get_future();
+ //boost::thread(func, boost::move(p)).detach();
+ boost::thread(func).detach();
+ BOOST_TEST(f.get() == 5);
+ }
+ return boost::report_errors();
+}
+
Added: trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Copyright (C) 2011 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// <boost/thread/future.hpp>
+
+// class promise<R>
+
+// void promise<void>::set_value_at_thread_exit();
+
+#define BOOST_THREAD_VERSION 4
+
+#include <boost/thread/future.hpp>
+#include <boost/detail/lightweight_test.hpp>
+
+int i = 0;
+
+boost::promise<void> p;
+void func()
+{
+ p.set_value_at_thread_exit();
+ i = 1;
+}
+
+void func2(boost::promise<void> p2)
+{
+ p2.set_value_at_thread_exit();
+ i = 1;
+}
+
+int main()
+{
+ try
+ {
+ boost::future<void> f = p.get_future();
+ boost::thread(func).detach();
+ f.get();
+ BOOST_TEST(i == 1);
+
+ }
+ catch(std::exception ex)
+ {
+ BOOST_TEST(false);
+ }
+ catch(...)
+ {
+ BOOST_TEST(false);
+ }
+
+ // BUG when moving promise. fixme
+// try
+// {
+// std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+// boost::promise<void> p2; // BUG
+// std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+// boost::future<void> f = p2.get_future();
+// std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+// boost::thread(func2, boost::move(p2)).detach(); // BUG
+// std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+// f.get();
+// std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+// BOOST_TEST(i == 1);
+// std::cout << __FILE__ << ":" << __LINE__ <<std::endl;
+//
+// }
+// catch(std::exception ex)
+// {
+// std::cout << __FILE__ << ":" << __LINE__ << " " << ex.what() << std::endl;
+// BOOST_TEST(false);
+// }
+// catch(...)
+// {
+// BOOST_TEST(false);
+// }
+ return boost::report_errors();
+}
+
Modified: trunk/libs/thread/test/test_4882.cpp
==============================================================================
--- trunk/libs/thread/test/test_4882.cpp (original)
+++ trunk/libs/thread/test/test_4882.cpp 2012-11-04 11:47:02 EST (Sun, 04 Nov 2012)
@@ -20,15 +20,28 @@
{
for (int i =0; i<10; ++i)
{
+#if 0
boost::system_time timeout = boost::get_system_time() + boost::posix_time::milliseconds(50);
if (mutex.timed_lock(timeout))
{
- std::cout << __FILE__ << ":" << __LINE__ << std::endl;
+ std::cout << __FILE__ << ":" << __LINE__ << " i="<<i << std::endl;
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
mutex.unlock();
- std::cout << __FILE__ << ":" << __LINE__ << std::endl;
+ std::cout << __FILE__ << ":" << __LINE__ << " i="<<i << std::endl;
}
+#else
+ boost::chrono::system_clock::time_point timeout = boost::chrono::system_clock::now() + boost::chrono::milliseconds(50);
+
+ std::cout << __FILE__ << ":" << __LINE__ << " i="<<i << std::endl;
+ if (mutex.try_lock_until(timeout))
+ {
+ std::cout << __FILE__ << ":" << __LINE__ << " i="<<i << std::endl;
+ boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
+ mutex.unlock();
+ std::cout << __FILE__ << ":" << __LINE__ << " i="<<i << std::endl;
+ }
+#endif
}
}
BOOST_CATCH (boost::lock_error& le)
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk