You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
1383 lines
37 KiB
1383 lines
37 KiB
// (C) Copyright 2008-10 Anthony Williams |
|
// |
|
// 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) |
|
|
|
#ifndef BOOST_THREAD_FUTURE_HPP |
|
#define BOOST_THREAD_FUTURE_HPP |
|
#include <stdexcept> |
|
#include <boost/thread/detail/move.hpp> |
|
#include <boost/thread/thread_time.hpp> |
|
#include <boost/thread/mutex.hpp> |
|
#include <boost/thread/condition_variable.hpp> |
|
#include <boost/exception_ptr.hpp> |
|
#include <boost/shared_ptr.hpp> |
|
#include <boost/scoped_ptr.hpp> |
|
#include <boost/type_traits/is_fundamental.hpp> |
|
#include <boost/type_traits/is_convertible.hpp> |
|
#include <boost/mpl/if.hpp> |
|
#include <boost/config.hpp> |
|
#include <boost/throw_exception.hpp> |
|
#include <algorithm> |
|
#include <boost/function.hpp> |
|
#include <boost/bind.hpp> |
|
#include <boost/ref.hpp> |
|
#include <boost/scoped_array.hpp> |
|
#include <boost/utility/enable_if.hpp> |
|
#include <list> |
|
#include <boost/next_prior.hpp> |
|
#include <vector> |
|
|
|
namespace boost |
|
{ |
|
class future_uninitialized: |
|
public std::logic_error |
|
{ |
|
public: |
|
future_uninitialized(): |
|
std::logic_error("Future Uninitialized") |
|
{} |
|
}; |
|
class broken_promise: |
|
public std::logic_error |
|
{ |
|
public: |
|
broken_promise(): |
|
std::logic_error("Broken promise") |
|
{} |
|
}; |
|
class future_already_retrieved: |
|
public std::logic_error |
|
{ |
|
public: |
|
future_already_retrieved(): |
|
std::logic_error("Future already retrieved") |
|
{} |
|
}; |
|
class promise_already_satisfied: |
|
public std::logic_error |
|
{ |
|
public: |
|
promise_already_satisfied(): |
|
std::logic_error("Promise already satisfied") |
|
{} |
|
}; |
|
|
|
class task_already_started: |
|
public std::logic_error |
|
{ |
|
public: |
|
task_already_started(): |
|
std::logic_error("Task already started") |
|
{} |
|
}; |
|
|
|
class task_moved: |
|
public std::logic_error |
|
{ |
|
public: |
|
task_moved(): |
|
std::logic_error("Task moved") |
|
{} |
|
}; |
|
|
|
namespace future_state |
|
{ |
|
enum state { uninitialized, waiting, ready, moved }; |
|
} |
|
|
|
namespace detail |
|
{ |
|
struct future_object_base |
|
{ |
|
boost::exception_ptr exception; |
|
bool done; |
|
boost::mutex mutex; |
|
boost::condition_variable waiters; |
|
typedef std::list<boost::condition_variable_any*> waiter_list; |
|
waiter_list external_waiters; |
|
boost::function<void()> callback; |
|
|
|
future_object_base(): |
|
done(false) |
|
{} |
|
virtual ~future_object_base() |
|
{} |
|
|
|
waiter_list::iterator register_external_waiter(boost::condition_variable_any& cv) |
|
{ |
|
boost::unique_lock<boost::mutex> lock(mutex); |
|
do_callback(lock); |
|
return external_waiters.insert(external_waiters.end(),&cv); |
|
} |
|
|
|
void remove_external_waiter(waiter_list::iterator it) |
|
{ |
|
boost::lock_guard<boost::mutex> lock(mutex); |
|
external_waiters.erase(it); |
|
} |
|
|
|
void mark_finished_internal() |
|
{ |
|
done=true; |
|
waiters.notify_all(); |
|
for(waiter_list::const_iterator it=external_waiters.begin(), |
|
end=external_waiters.end();it!=end;++it) |
|
{ |
|
(*it)->notify_all(); |
|
} |
|
} |
|
|
|
struct relocker |
|
{ |
|
boost::unique_lock<boost::mutex>& lock; |
|
|
|
relocker(boost::unique_lock<boost::mutex>& lock_): |
|
lock(lock_) |
|
{ |
|
lock.unlock(); |
|
} |
|
~relocker() |
|
{ |
|
lock.lock(); |
|
} |
|
private: |
|
relocker& operator=(relocker const&); |
|
}; |
|
|
|
void do_callback(boost::unique_lock<boost::mutex>& lock) |
|
{ |
|
if(callback && !done) |
|
{ |
|
boost::function<void()> local_callback=callback; |
|
relocker relock(lock); |
|
local_callback(); |
|
} |
|
} |
|
|
|
|
|
void wait(bool rethrow=true) |
|
{ |
|
boost::unique_lock<boost::mutex> lock(mutex); |
|
do_callback(lock); |
|
while(!done) |
|
{ |
|
waiters.wait(lock); |
|
} |
|
if(rethrow && exception) |
|
{ |
|
boost::rethrow_exception(exception); |
|
} |
|
} |
|
|
|
bool timed_wait_until(boost::system_time const& target_time) |
|
{ |
|
boost::unique_lock<boost::mutex> lock(mutex); |
|
do_callback(lock); |
|
while(!done) |
|
{ |
|
bool const success=waiters.timed_wait(lock,target_time); |
|
if(!success && !done) |
|
{ |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
void mark_exceptional_finish_internal(boost::exception_ptr const& e) |
|
{ |
|
exception=e; |
|
mark_finished_internal(); |
|
} |
|
void mark_exceptional_finish() |
|
{ |
|
boost::lock_guard<boost::mutex> lock(mutex); |
|
mark_exceptional_finish_internal(boost::current_exception()); |
|
} |
|
|
|
bool has_value() |
|
{ |
|
boost::lock_guard<boost::mutex> lock(mutex); |
|
return done && !exception; |
|
} |
|
bool has_exception() |
|
{ |
|
boost::lock_guard<boost::mutex> lock(mutex); |
|
return done && exception; |
|
} |
|
|
|
template<typename F,typename U> |
|
void set_wait_callback(F f,U* u) |
|
{ |
|
callback=boost::bind(f,boost::ref(*u)); |
|
} |
|
|
|
private: |
|
future_object_base(future_object_base const&); |
|
future_object_base& operator=(future_object_base const&); |
|
}; |
|
|
|
template<typename T> |
|
struct future_traits |
|
{ |
|
typedef boost::scoped_ptr<T> storage_type; |
|
#ifndef BOOST_NO_RVALUE_REFERENCES |
|
typedef T const& source_reference_type; |
|
struct dummy; |
|
typedef typename boost::mpl::if_<boost::is_fundamental<T>,dummy&,T&&>::type rvalue_source_type; |
|
typedef typename boost::mpl::if_<boost::is_fundamental<T>,T,T&&>::type move_dest_type; |
|
#else |
|
typedef T& source_reference_type; |
|
typedef typename boost::mpl::if_<boost::is_convertible<T&,boost::detail::thread_move_t<T> >,boost::detail::thread_move_t<T>,T const&>::type rvalue_source_type; |
|
typedef typename boost::mpl::if_<boost::is_convertible<T&,boost::detail::thread_move_t<T> >,boost::detail::thread_move_t<T>,T>::type move_dest_type; |
|
#endif |
|
|
|
static void init(storage_type& storage,source_reference_type t) |
|
{ |
|
storage.reset(new T(t)); |
|
} |
|
|
|
static void init(storage_type& storage,rvalue_source_type t) |
|
{ |
|
storage.reset(new T(static_cast<rvalue_source_type>(t))); |
|
} |
|
|
|
static void cleanup(storage_type& storage) |
|
{ |
|
storage.reset(); |
|
} |
|
}; |
|
|
|
template<typename T> |
|
struct future_traits<T&> |
|
{ |
|
typedef T* storage_type; |
|
typedef T& source_reference_type; |
|
struct rvalue_source_type |
|
{}; |
|
typedef T& move_dest_type; |
|
|
|
static void init(storage_type& storage,T& t) |
|
{ |
|
storage=&t; |
|
} |
|
|
|
static void cleanup(storage_type& storage) |
|
{ |
|
storage=0; |
|
} |
|
}; |
|
|
|
template<> |
|
struct future_traits<void> |
|
{ |
|
typedef bool storage_type; |
|
typedef void move_dest_type; |
|
|
|
static void init(storage_type& storage) |
|
{ |
|
storage=true; |
|
} |
|
|
|
static void cleanup(storage_type& storage) |
|
{ |
|
storage=false; |
|
} |
|
|
|
}; |
|
|
|
template<typename T> |
|
struct future_object: |
|
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; |
|
|
|
storage_type result; |
|
|
|
future_object(): |
|
result(0) |
|
{} |
|
|
|
void mark_finished_with_result_internal(source_reference_type result_) |
|
{ |
|
future_traits<T>::init(result,result_); |
|
mark_finished_internal(); |
|
} |
|
void mark_finished_with_result_internal(rvalue_source_type result_) |
|
{ |
|
future_traits<T>::init(result,static_cast<rvalue_source_type>(result_)); |
|
mark_finished_internal(); |
|
} |
|
|
|
void mark_finished_with_result(source_reference_type result_) |
|
{ |
|
boost::lock_guard<boost::mutex> lock(mutex); |
|
mark_finished_with_result_internal(result_); |
|
} |
|
void mark_finished_with_result(rvalue_source_type result_) |
|
{ |
|
boost::lock_guard<boost::mutex> lock(mutex); |
|
mark_finished_with_result_internal(result_); |
|
} |
|
|
|
move_dest_type get() |
|
{ |
|
wait(); |
|
return static_cast<move_dest_type>(*result); |
|
} |
|
|
|
future_state::state get_state() |
|
{ |
|
boost::lock_guard<boost::mutex> guard(mutex); |
|
if(!done) |
|
{ |
|
return future_state::waiting; |
|
} |
|
else |
|
{ |
|
return future_state::ready; |
|
} |
|
} |
|
|
|
private: |
|
future_object(future_object const&); |
|
future_object& operator=(future_object const&); |
|
}; |
|
|
|
template<> |
|
struct future_object<void>: |
|
detail::future_object_base |
|
{ |
|
future_object() |
|
{} |
|
|
|
void mark_finished_with_result_internal() |
|
{ |
|
mark_finished_internal(); |
|
} |
|
|
|
void mark_finished_with_result() |
|
{ |
|
boost::lock_guard<boost::mutex> lock(mutex); |
|
mark_finished_with_result_internal(); |
|
} |
|
|
|
void get() |
|
{ |
|
wait(); |
|
} |
|
|
|
future_state::state get_state() |
|
{ |
|
boost::lock_guard<boost::mutex> guard(mutex); |
|
if(!done) |
|
{ |
|
return future_state::waiting; |
|
} |
|
else |
|
{ |
|
return future_state::ready; |
|
} |
|
} |
|
|
|
private: |
|
future_object(future_object const&); |
|
future_object& operator=(future_object const&); |
|
}; |
|
|
|
class future_waiter |
|
{ |
|
struct registered_waiter; |
|
typedef std::vector<registered_waiter>::size_type count_type; |
|
|
|
struct registered_waiter |
|
{ |
|
boost::shared_ptr<detail::future_object_base> future; |
|
detail::future_object_base::waiter_list::iterator wait_iterator; |
|
count_type index; |
|
|
|
registered_waiter(boost::shared_ptr<detail::future_object_base> const& future_, |
|
detail::future_object_base::waiter_list::iterator wait_iterator_, |
|
count_type index_): |
|
future(future_),wait_iterator(wait_iterator_),index(index_) |
|
{} |
|
|
|
}; |
|
|
|
struct all_futures_lock |
|
{ |
|
count_type count; |
|
boost::scoped_array<boost::unique_lock<boost::mutex> > locks; |
|
|
|
all_futures_lock(std::vector<registered_waiter>& futures): |
|
count(futures.size()),locks(new boost::unique_lock<boost::mutex>[count]) |
|
{ |
|
for(count_type i=0;i<count;++i) |
|
{ |
|
locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex); |
|
} |
|
} |
|
|
|
void lock() |
|
{ |
|
boost::lock(locks.get(),locks.get()+count); |
|
} |
|
|
|
void unlock() |
|
{ |
|
for(count_type i=0;i<count;++i) |
|
{ |
|
locks[i].unlock(); |
|
} |
|
} |
|
}; |
|
|
|
boost::condition_variable_any cv; |
|
std::vector<registered_waiter> futures; |
|
count_type future_count; |
|
|
|
public: |
|
future_waiter(): |
|
future_count(0) |
|
{} |
|
|
|
template<typename F> |
|
void add(F& f) |
|
{ |
|
if(f.future) |
|
{ |
|
futures.push_back(registered_waiter(f.future,f.future->register_external_waiter(cv),future_count)); |
|
} |
|
++future_count; |
|
} |
|
|
|
count_type wait() |
|
{ |
|
all_futures_lock lk(futures); |
|
for(;;) |
|
{ |
|
for(count_type i=0;i<futures.size();++i) |
|
{ |
|
if(futures[i].future->done) |
|
{ |
|
return futures[i].index; |
|
} |
|
} |
|
cv.wait(lk); |
|
} |
|
} |
|
|
|
~future_waiter() |
|
{ |
|
for(count_type i=0;i<futures.size();++i) |
|
{ |
|
futures[i].future->remove_external_waiter(futures[i].wait_iterator); |
|
} |
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
template <typename R> |
|
class unique_future; |
|
|
|
template <typename R> |
|
class shared_future; |
|
|
|
template<typename T> |
|
struct is_future_type |
|
{ |
|
BOOST_STATIC_CONSTANT(bool, value=false); |
|
}; |
|
|
|
template<typename T> |
|
struct is_future_type<unique_future<T> > |
|
{ |
|
BOOST_STATIC_CONSTANT(bool, value=true); |
|
}; |
|
|
|
template<typename T> |
|
struct is_future_type<shared_future<T> > |
|
{ |
|
BOOST_STATIC_CONSTANT(bool, value=true); |
|
}; |
|
|
|
template<typename Iterator> |
|
typename boost::disable_if<is_future_type<Iterator>,void>::type wait_for_all(Iterator begin,Iterator end) |
|
{ |
|
for(Iterator current=begin;current!=end;++current) |
|
{ |
|
current->wait(); |
|
} |
|
} |
|
|
|
template<typename F1,typename F2> |
|
typename boost::enable_if<is_future_type<F1>,void>::type wait_for_all(F1& f1,F2& f2) |
|
{ |
|
f1.wait(); |
|
f2.wait(); |
|
} |
|
|
|
template<typename F1,typename F2,typename F3> |
|
void wait_for_all(F1& f1,F2& f2,F3& f3) |
|
{ |
|
f1.wait(); |
|
f2.wait(); |
|
f3.wait(); |
|
} |
|
|
|
template<typename F1,typename F2,typename F3,typename F4> |
|
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4) |
|
{ |
|
f1.wait(); |
|
f2.wait(); |
|
f3.wait(); |
|
f4.wait(); |
|
} |
|
|
|
template<typename F1,typename F2,typename F3,typename F4,typename F5> |
|
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5) |
|
{ |
|
f1.wait(); |
|
f2.wait(); |
|
f3.wait(); |
|
f4.wait(); |
|
f5.wait(); |
|
} |
|
|
|
template<typename Iterator> |
|
typename boost::disable_if<is_future_type<Iterator>,Iterator>::type wait_for_any(Iterator begin,Iterator end) |
|
{ |
|
if(begin==end) |
|
return end; |
|
|
|
detail::future_waiter waiter; |
|
for(Iterator current=begin;current!=end;++current) |
|
{ |
|
waiter.add(*current); |
|
} |
|
return boost::next(begin,waiter.wait()); |
|
} |
|
|
|
template<typename F1,typename F2> |
|
typename boost::enable_if<is_future_type<F1>,unsigned>::type wait_for_any(F1& f1,F2& f2) |
|
{ |
|
detail::future_waiter waiter; |
|
waiter.add(f1); |
|
waiter.add(f2); |
|
return waiter.wait(); |
|
} |
|
|
|
template<typename F1,typename F2,typename F3> |
|
unsigned wait_for_any(F1& f1,F2& f2,F3& f3) |
|
{ |
|
detail::future_waiter waiter; |
|
waiter.add(f1); |
|
waiter.add(f2); |
|
waiter.add(f3); |
|
return waiter.wait(); |
|
} |
|
|
|
template<typename F1,typename F2,typename F3,typename F4> |
|
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4) |
|
{ |
|
detail::future_waiter waiter; |
|
waiter.add(f1); |
|
waiter.add(f2); |
|
waiter.add(f3); |
|
waiter.add(f4); |
|
return waiter.wait(); |
|
} |
|
|
|
template<typename F1,typename F2,typename F3,typename F4,typename F5> |
|
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5) |
|
{ |
|
detail::future_waiter waiter; |
|
waiter.add(f1); |
|
waiter.add(f2); |
|
waiter.add(f3); |
|
waiter.add(f4); |
|
waiter.add(f5); |
|
return waiter.wait(); |
|
} |
|
|
|
template <typename R> |
|
class promise; |
|
|
|
template <typename R> |
|
class packaged_task; |
|
|
|
template <typename R> |
|
class unique_future |
|
{ |
|
unique_future(unique_future & rhs);// = delete; |
|
unique_future& operator=(unique_future& rhs);// = delete; |
|
|
|
typedef boost::shared_ptr<detail::future_object<R> > future_ptr; |
|
|
|
future_ptr future; |
|
|
|
friend class shared_future<R>; |
|
friend class promise<R>; |
|
friend class packaged_task<R>; |
|
friend class detail::future_waiter; |
|
|
|
typedef typename detail::future_traits<R>::move_dest_type move_dest_type; |
|
|
|
unique_future(future_ptr future_): |
|
future(future_) |
|
{} |
|
|
|
public: |
|
typedef future_state::state state; |
|
|
|
unique_future() |
|
{} |
|
|
|
~unique_future() |
|
{} |
|
|
|
#ifndef BOOST_NO_RVALUE_REFERENCES |
|
unique_future(unique_future && other) |
|
{ |
|
future.swap(other.future); |
|
} |
|
unique_future& operator=(unique_future && other) |
|
{ |
|
future=other.future; |
|
other.future.reset(); |
|
return *this; |
|
} |
|
#else |
|
unique_future(boost::detail::thread_move_t<unique_future> other): |
|
future(other->future) |
|
{ |
|
other->future.reset(); |
|
} |
|
|
|
unique_future& operator=(boost::detail::thread_move_t<unique_future> other) |
|
{ |
|
future=other->future; |
|
other->future.reset(); |
|
return *this; |
|
} |
|
|
|
operator boost::detail::thread_move_t<unique_future>() |
|
{ |
|
return boost::detail::thread_move_t<unique_future>(*this); |
|
} |
|
#endif |
|
|
|
void swap(unique_future& other) |
|
{ |
|
future.swap(other.future); |
|
} |
|
|
|
// retrieving the value |
|
move_dest_type get() |
|
{ |
|
if(!future) |
|
{ |
|
boost::throw_exception(future_uninitialized()); |
|
} |
|
|
|
return future->get(); |
|
} |
|
|
|
// functions to check state, and wait for ready |
|
state get_state() const |
|
{ |
|
if(!future) |
|
{ |
|
return future_state::uninitialized; |
|
} |
|
return future->get_state(); |
|
} |
|
|
|
|
|
bool is_ready() const |
|
{ |
|
return get_state()==future_state::ready; |
|
} |
|
|
|
bool has_exception() const |
|
{ |
|
return future && future->has_exception(); |
|
} |
|
|
|
bool has_value() const |
|
{ |
|
return future && future->has_value(); |
|
} |
|
|
|
void wait() const |
|
{ |
|
if(!future) |
|
{ |
|
boost::throw_exception(future_uninitialized()); |
|
} |
|
future->wait(false); |
|
} |
|
|
|
template<typename Duration> |
|
bool timed_wait(Duration const& rel_time) const |
|
{ |
|
return timed_wait_until(boost::get_system_time()+rel_time); |
|
} |
|
|
|
bool timed_wait_until(boost::system_time const& abs_time) const |
|
{ |
|
if(!future) |
|
{ |
|
boost::throw_exception(future_uninitialized()); |
|
} |
|
return future->timed_wait_until(abs_time); |
|
} |
|
|
|
}; |
|
|
|
template <typename R> |
|
class shared_future |
|
{ |
|
typedef boost::shared_ptr<detail::future_object<R> > future_ptr; |
|
|
|
future_ptr future; |
|
|
|
// shared_future(const unique_future<R>& other); |
|
// shared_future& operator=(const unique_future<R>& other); |
|
|
|
friend class detail::future_waiter; |
|
friend class promise<R>; |
|
friend class packaged_task<R>; |
|
|
|
shared_future(future_ptr future_): |
|
future(future_) |
|
{} |
|
|
|
public: |
|
shared_future(shared_future const& other): |
|
future(other.future) |
|
{} |
|
|
|
typedef future_state::state state; |
|
|
|
shared_future() |
|
{} |
|
|
|
~shared_future() |
|
{} |
|
|
|
shared_future& operator=(shared_future const& other) |
|
{ |
|
future=other.future; |
|
return *this; |
|
} |
|
#ifndef BOOST_NO_RVALUE_REFERENCES |
|
shared_future(shared_future && other) |
|
{ |
|
future.swap(other.future); |
|
} |
|
shared_future(unique_future<R> && other) |
|
{ |
|
future.swap(other.future); |
|
} |
|
shared_future& operator=(shared_future && other) |
|
{ |
|
future.swap(other.future); |
|
other.future.reset(); |
|
return *this; |
|
} |
|
shared_future& operator=(unique_future<R> && other) |
|
{ |
|
future.swap(other.future); |
|
other.future.reset(); |
|
return *this; |
|
} |
|
#else |
|
shared_future(boost::detail::thread_move_t<shared_future> other): |
|
future(other->future) |
|
{ |
|
other->future.reset(); |
|
} |
|
// shared_future(const unique_future<R> &) = delete; |
|
shared_future(boost::detail::thread_move_t<unique_future<R> > other): |
|
future(other->future) |
|
{ |
|
other->future.reset(); |
|
} |
|
shared_future& operator=(boost::detail::thread_move_t<shared_future> other) |
|
{ |
|
future.swap(other->future); |
|
other->future.reset(); |
|
return *this; |
|
} |
|
shared_future& operator=(boost::detail::thread_move_t<unique_future<R> > other) |
|
{ |
|
future.swap(other->future); |
|
other->future.reset(); |
|
return *this; |
|
} |
|
|
|
operator boost::detail::thread_move_t<shared_future>() |
|
{ |
|
return boost::detail::thread_move_t<shared_future>(*this); |
|
} |
|
|
|
#endif |
|
|
|
void swap(shared_future& other) |
|
{ |
|
future.swap(other.future); |
|
} |
|
|
|
// retrieving the value |
|
R get() |
|
{ |
|
if(!future) |
|
{ |
|
boost::throw_exception(future_uninitialized()); |
|
} |
|
|
|
return future->get(); |
|
} |
|
|
|
// functions to check state, and wait for ready |
|
state get_state() const |
|
{ |
|
if(!future) |
|
{ |
|
return future_state::uninitialized; |
|
} |
|
return future->get_state(); |
|
} |
|
|
|
|
|
bool is_ready() const |
|
{ |
|
return get_state()==future_state::ready; |
|
} |
|
|
|
bool has_exception() const |
|
{ |
|
return future && future->has_exception(); |
|
} |
|
|
|
bool has_value() const |
|
{ |
|
return future && future->has_value(); |
|
} |
|
|
|
void wait() const |
|
{ |
|
if(!future) |
|
{ |
|
boost::throw_exception(future_uninitialized()); |
|
} |
|
future->wait(false); |
|
} |
|
|
|
template<typename Duration> |
|
bool timed_wait(Duration const& rel_time) const |
|
{ |
|
return timed_wait_until(boost::get_system_time()+rel_time); |
|
} |
|
|
|
bool timed_wait_until(boost::system_time const& abs_time) const |
|
{ |
|
if(!future) |
|
{ |
|
boost::throw_exception(future_uninitialized()); |
|
} |
|
return future->timed_wait_until(abs_time); |
|
} |
|
|
|
}; |
|
|
|
template <typename R> |
|
class promise |
|
{ |
|
typedef boost::shared_ptr<detail::future_object<R> > future_ptr; |
|
|
|
future_ptr future; |
|
bool future_obtained; |
|
|
|
promise(promise & rhs);// = delete; |
|
promise & operator=(promise & rhs);// = delete; |
|
|
|
void lazy_init() |
|
{ |
|
if(!atomic_load(&future)) |
|
{ |
|
future_ptr blank; |
|
atomic_compare_exchange(&future,&blank,future_ptr(new detail::future_object<R>)); |
|
} |
|
} |
|
|
|
public: |
|
// template <class Allocator> explicit promise(Allocator a); |
|
|
|
promise(): |
|
future(),future_obtained(false) |
|
{} |
|
|
|
~promise() |
|
{ |
|
if(future) |
|
{ |
|
boost::lock_guard<boost::mutex> lock(future->mutex); |
|
|
|
if(!future->done) |
|
{ |
|
future->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); |
|
} |
|
} |
|
} |
|
|
|
// Assignment |
|
#ifndef BOOST_NO_RVALUE_REFERENCES |
|
promise(promise && rhs): |
|
future_obtained(rhs.future_obtained) |
|
{ |
|
future.swap(rhs.future); |
|
rhs.future_obtained=false; |
|
} |
|
promise & operator=(promise&& rhs) |
|
{ |
|
future.swap(rhs.future); |
|
future_obtained=rhs.future_obtained; |
|
rhs.future.reset(); |
|
rhs.future_obtained=false; |
|
return *this; |
|
} |
|
#else |
|
promise(boost::detail::thread_move_t<promise> rhs): |
|
future(rhs->future),future_obtained(rhs->future_obtained) |
|
{ |
|
rhs->future.reset(); |
|
rhs->future_obtained=false; |
|
} |
|
promise & operator=(boost::detail::thread_move_t<promise> rhs) |
|
{ |
|
future=rhs->future; |
|
future_obtained=rhs->future_obtained; |
|
rhs->future.reset(); |
|
rhs->future_obtained=false; |
|
return *this; |
|
} |
|
|
|
operator boost::detail::thread_move_t<promise>() |
|
{ |
|
return boost::detail::thread_move_t<promise>(*this); |
|
} |
|
#endif |
|
|
|
void swap(promise& other) |
|
{ |
|
future.swap(other.future); |
|
std::swap(future_obtained,other.future_obtained); |
|
} |
|
|
|
// Result retrieval |
|
unique_future<R> get_future() |
|
{ |
|
lazy_init(); |
|
if(future_obtained) |
|
{ |
|
boost::throw_exception(future_already_retrieved()); |
|
} |
|
future_obtained=true; |
|
return unique_future<R>(future); |
|
} |
|
|
|
void set_value(typename detail::future_traits<R>::source_reference_type r) |
|
{ |
|
lazy_init(); |
|
boost::lock_guard<boost::mutex> lock(future->mutex); |
|
if(future->done) |
|
{ |
|
boost::throw_exception(promise_already_satisfied()); |
|
} |
|
future->mark_finished_with_result_internal(r); |
|
} |
|
|
|
// void set_value(R && r); |
|
void set_value(typename detail::future_traits<R>::rvalue_source_type r) |
|
{ |
|
lazy_init(); |
|
boost::lock_guard<boost::mutex> lock(future->mutex); |
|
if(future->done) |
|
{ |
|
boost::throw_exception(promise_already_satisfied()); |
|
} |
|
future->mark_finished_with_result_internal(static_cast<typename detail::future_traits<R>::rvalue_source_type>(r)); |
|
} |
|
|
|
void set_exception(boost::exception_ptr p) |
|
{ |
|
lazy_init(); |
|
boost::lock_guard<boost::mutex> lock(future->mutex); |
|
if(future->done) |
|
{ |
|
boost::throw_exception(promise_already_satisfied()); |
|
} |
|
future->mark_exceptional_finish_internal(p); |
|
} |
|
|
|
template<typename F> |
|
void set_wait_callback(F f) |
|
{ |
|
lazy_init(); |
|
future->set_wait_callback(f,this); |
|
} |
|
|
|
}; |
|
|
|
template <> |
|
class promise<void> |
|
{ |
|
typedef boost::shared_ptr<detail::future_object<void> > future_ptr; |
|
|
|
future_ptr future; |
|
bool future_obtained; |
|
|
|
promise(promise & rhs);// = delete; |
|
promise & operator=(promise & rhs);// = delete; |
|
|
|
void lazy_init() |
|
{ |
|
if(!atomic_load(&future)) |
|
{ |
|
future_ptr blank; |
|
atomic_compare_exchange(&future,&blank,future_ptr(new detail::future_object<void>)); |
|
} |
|
} |
|
public: |
|
// template <class Allocator> explicit promise(Allocator a); |
|
|
|
promise(): |
|
future(),future_obtained(false) |
|
{} |
|
|
|
~promise() |
|
{ |
|
if(future) |
|
{ |
|
boost::lock_guard<boost::mutex> lock(future->mutex); |
|
|
|
if(!future->done) |
|
{ |
|
future->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); |
|
} |
|
} |
|
} |
|
|
|
// Assignment |
|
#ifndef BOOST_NO_RVALUE_REFERENCES |
|
promise(promise && rhs): |
|
future_obtained(rhs.future_obtained) |
|
{ |
|
future.swap(rhs.future); |
|
rhs.future_obtained=false; |
|
} |
|
promise & operator=(promise&& rhs) |
|
{ |
|
future.swap(rhs.future); |
|
future_obtained=rhs.future_obtained; |
|
rhs.future.reset(); |
|
rhs.future_obtained=false; |
|
return *this; |
|
} |
|
#else |
|
promise(boost::detail::thread_move_t<promise> rhs): |
|
future(rhs->future),future_obtained(rhs->future_obtained) |
|
{ |
|
rhs->future.reset(); |
|
rhs->future_obtained=false; |
|
} |
|
promise & operator=(boost::detail::thread_move_t<promise> rhs) |
|
{ |
|
future=rhs->future; |
|
future_obtained=rhs->future_obtained; |
|
rhs->future.reset(); |
|
rhs->future_obtained=false; |
|
return *this; |
|
} |
|
|
|
operator boost::detail::thread_move_t<promise>() |
|
{ |
|
return boost::detail::thread_move_t<promise>(*this); |
|
} |
|
#endif |
|
|
|
void swap(promise& other) |
|
{ |
|
future.swap(other.future); |
|
std::swap(future_obtained,other.future_obtained); |
|
} |
|
|
|
// Result retrieval |
|
unique_future<void> get_future() |
|
{ |
|
lazy_init(); |
|
|
|
if(future_obtained) |
|
{ |
|
boost::throw_exception(future_already_retrieved()); |
|
} |
|
future_obtained=true; |
|
return unique_future<void>(future); |
|
} |
|
|
|
void set_value() |
|
{ |
|
lazy_init(); |
|
boost::lock_guard<boost::mutex> lock(future->mutex); |
|
if(future->done) |
|
{ |
|
boost::throw_exception(promise_already_satisfied()); |
|
} |
|
future->mark_finished_with_result_internal(); |
|
} |
|
|
|
void set_exception(boost::exception_ptr p) |
|
{ |
|
lazy_init(); |
|
boost::lock_guard<boost::mutex> lock(future->mutex); |
|
if(future->done) |
|
{ |
|
boost::throw_exception(promise_already_satisfied()); |
|
} |
|
future->mark_exceptional_finish_internal(p); |
|
} |
|
|
|
template<typename F> |
|
void set_wait_callback(F f) |
|
{ |
|
lazy_init(); |
|
future->set_wait_callback(f,this); |
|
} |
|
|
|
}; |
|
|
|
namespace detail |
|
{ |
|
template<typename R> |
|
struct task_base: |
|
detail::future_object<R> |
|
{ |
|
bool started; |
|
|
|
task_base(): |
|
started(false) |
|
{} |
|
|
|
void run() |
|
{ |
|
{ |
|
boost::lock_guard<boost::mutex> lk(this->mutex); |
|
if(started) |
|
{ |
|
boost::throw_exception(task_already_started()); |
|
} |
|
started=true; |
|
} |
|
do_run(); |
|
} |
|
|
|
void owner_destroyed() |
|
{ |
|
boost::lock_guard<boost::mutex> lk(this->mutex); |
|
if(!started) |
|
{ |
|
started=true; |
|
this->mark_exceptional_finish_internal(boost::copy_exception(boost::broken_promise())); |
|
} |
|
} |
|
|
|
|
|
virtual void do_run()=0; |
|
}; |
|
|
|
|
|
template<typename R,typename F> |
|
struct task_object: |
|
task_base<R> |
|
{ |
|
F f; |
|
task_object(F const& f_): |
|
f(f_) |
|
{} |
|
task_object(boost::detail::thread_move_t<F> f_): |
|
f(f_) |
|
{} |
|
|
|
void do_run() |
|
{ |
|
try |
|
{ |
|
this->mark_finished_with_result(f()); |
|
} |
|
catch(...) |
|
{ |
|
this->mark_exceptional_finish(); |
|
} |
|
} |
|
}; |
|
|
|
template<typename F> |
|
struct task_object<void,F>: |
|
task_base<void> |
|
{ |
|
F f; |
|
task_object(F const& f_): |
|
f(f_) |
|
{} |
|
task_object(boost::detail::thread_move_t<F> f_): |
|
f(f_) |
|
{} |
|
|
|
void do_run() |
|
{ |
|
try |
|
{ |
|
f(); |
|
this->mark_finished_with_result(); |
|
} |
|
catch(...) |
|
{ |
|
this->mark_exceptional_finish(); |
|
} |
|
} |
|
}; |
|
|
|
} |
|
|
|
|
|
template<typename R> |
|
class packaged_task |
|
{ |
|
boost::shared_ptr<detail::task_base<R> > task; |
|
bool future_obtained; |
|
|
|
packaged_task(packaged_task&);// = delete; |
|
packaged_task& operator=(packaged_task&);// = delete; |
|
|
|
public: |
|
packaged_task(): |
|
future_obtained(false) |
|
{} |
|
|
|
// construction and destruction |
|
template <class F> |
|
explicit packaged_task(F const& f): |
|
task(new detail::task_object<R,F>(f)),future_obtained(false) |
|
{} |
|
explicit packaged_task(R(*f)()): |
|
task(new detail::task_object<R,R(*)()>(f)),future_obtained(false) |
|
{} |
|
|
|
template <class F> |
|
explicit packaged_task(boost::detail::thread_move_t<F> f): |
|
task(new detail::task_object<R,F>(f)),future_obtained(false) |
|
{} |
|
|
|
// template <class F, class Allocator> |
|
// explicit packaged_task(F const& f, Allocator a); |
|
// template <class F, class Allocator> |
|
// explicit packaged_task(F&& f, Allocator a); |
|
|
|
|
|
~packaged_task() |
|
{ |
|
if(task) |
|
{ |
|
task->owner_destroyed(); |
|
} |
|
} |
|
|
|
// assignment |
|
#ifndef BOOST_NO_RVALUE_REFERENCES |
|
packaged_task(packaged_task&& other): |
|
future_obtained(other.future_obtained) |
|
{ |
|
task.swap(other.task); |
|
other.future_obtained=false; |
|
} |
|
packaged_task& operator=(packaged_task&& other) |
|
{ |
|
packaged_task temp(static_cast<packaged_task&&>(other)); |
|
swap(temp); |
|
return *this; |
|
} |
|
#else |
|
packaged_task(boost::detail::thread_move_t<packaged_task> other): |
|
future_obtained(other->future_obtained) |
|
{ |
|
task.swap(other->task); |
|
other->future_obtained=false; |
|
} |
|
packaged_task& operator=(boost::detail::thread_move_t<packaged_task> other) |
|
{ |
|
packaged_task temp(other); |
|
swap(temp); |
|
return *this; |
|
} |
|
operator boost::detail::thread_move_t<packaged_task>() |
|
{ |
|
return boost::detail::thread_move_t<packaged_task>(*this); |
|
} |
|
#endif |
|
|
|
void swap(packaged_task& other) |
|
{ |
|
task.swap(other.task); |
|
std::swap(future_obtained,other.future_obtained); |
|
} |
|
|
|
// result retrieval |
|
unique_future<R> get_future() |
|
{ |
|
if(!task) |
|
{ |
|
boost::throw_exception(task_moved()); |
|
} |
|
else if(!future_obtained) |
|
{ |
|
future_obtained=true; |
|
return unique_future<R>(task); |
|
} |
|
else |
|
{ |
|
boost::throw_exception(future_already_retrieved()); |
|
} |
|
} |
|
|
|
|
|
// execution |
|
void operator()() |
|
{ |
|
if(!task) |
|
{ |
|
boost::throw_exception(task_moved()); |
|
} |
|
task->run(); |
|
} |
|
|
|
template<typename F> |
|
void set_wait_callback(F f) |
|
{ |
|
task->set_wait_callback(f,this); |
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
#endif
|
|
|