Bytemaster's Boost Libraries
|
00001 #ifndef _BOOST_CMT_FUTURE_HPP 00002 #define _BOOST_CMT_FUTURE_HPP 00003 #include <boost/cmt/retainable.hpp> 00004 #include <boost/cmt/error.hpp> 00005 #include <boost/thread/mutex.hpp> 00006 #include <boost/cmt/mutex.hpp> 00007 #include <boost/optional.hpp> 00008 #include <boost/chrono.hpp> 00009 00010 namespace boost { namespace cmt { 00011 using boost::chrono::microseconds; 00012 00013 class abstract_thread; 00014 class promise_base : public retainable { 00015 public: 00016 typedef retainable_ptr<promise_base> ptr; 00017 promise_base():m_blocked_thread(0),m_timeout(microseconds::max()){} 00018 virtual ~promise_base(){} 00019 00020 virtual bool ready()const = 0; 00021 protected: 00022 void enqueue_thread(); 00023 void wait( const microseconds& timeout_us ); 00024 void notify(); 00025 virtual void set_timeout()=0; 00026 virtual void set_exception( const boost::exception_ptr& e )=0; 00027 00028 private: 00029 friend class thread; 00030 friend class thread_private; 00031 00032 abstract_thread* m_blocked_thread; 00033 microseconds m_timeout; 00034 }; 00035 00036 struct void_t {}; 00037 00038 template<typename T = void_t> 00039 class promise : public promise_base { 00040 public: 00041 typedef retainable_ptr<promise> ptr; 00042 00043 promise(){} 00044 promise( const T& v ):m_value(v){} 00045 00046 bool ready()const { 00047 boost::unique_lock<mutex> lock( m_mutex ); 00048 return !!m_value || m_error; 00049 } 00050 bool error()const { return m_error; } 00051 operator const T&()const { return wait(); } 00052 00053 const T& wait(const microseconds& timeout = microseconds::max() ) { 00054 { // lock while we check values 00055 boost::unique_lock<mutex> lock( m_mutex ); 00056 if( m_error ) boost::rethrow_exception(m_error); 00057 if( m_value ) return *m_value; 00058 enqueue_thread(); 00059 } // unlock before yielding, but after enqueing 00060 promise_base::wait(timeout); 00061 if( m_error ) boost::rethrow_exception(m_error); 00062 if( m_value ) return *m_value; 00063 BOOST_THROW_EXCEPTION( error::future_value_not_ready() ); 00064 return *m_value; 00065 } 00066 void set_exception( const boost::exception_ptr& e ) { 00067 { 00068 boost::unique_lock<mutex> lock( m_mutex ); 00069 m_error = e; 00070 } 00071 notify(); 00072 } 00073 void set_value( const T& v ) { 00074 { 00075 boost::unique_lock<mutex> lock( m_mutex ); 00076 if( m_error ) 00077 return; 00078 m_value = v; 00079 } 00080 notify(); 00081 } 00082 00083 private: 00084 void set_timeout() { 00085 { 00086 boost::unique_lock<mutex> lock( m_mutex ); 00087 if( m_value ) 00088 return; 00089 m_error = boost::copy_exception( error::future_wait_timeout() ); 00090 } 00091 notify(); 00092 } 00093 00094 mutable mutex m_mutex; 00095 boost::exception_ptr m_error; 00096 boost::optional<T> m_value; 00097 }; 00098 00099 template<> 00100 class promise<void> : public promise<void_t> {}; 00101 00124 template<typename T = void_t> 00125 class future { 00126 public: 00127 typedef typename promise<T>::ptr promise_ptr; 00128 typedef T value_type; 00129 00130 future( const promise_ptr& p = promise_ptr() ) 00131 :m_prom(p){} 00132 future( const T& v ):m_prom( new promise<T>(v) ){} 00133 00134 bool valid()const { return !!m_prom; } 00135 bool ready()const { return m_prom->ready();} 00136 bool error()const { return valid() ? m_prom->error() : false; } 00137 operator const T&()const { 00138 if( !m_prom ) BOOST_THROW_EXCEPTION( error::null_future() ); 00139 return m_prom->wait(); 00140 } 00141 const T& wait(const microseconds& timeout = microseconds::max() ) { 00142 if( !m_prom ) BOOST_THROW_EXCEPTION( error::null_future() ); 00143 return m_prom->wait(timeout); 00144 } 00145 00146 private: 00147 promise_ptr m_prom; 00148 }; 00149 00150 template<> 00151 class future<void> : public future<void_t> { 00152 public: 00153 future( const promise<void_t>::ptr& p = promise<void_t>::ptr() ) 00154 :future<void_t>(p){} 00155 future( const void_t& v ):future<void_t>(v){} 00156 }; 00157 00158 00159 } } 00160 00161 00162 #endif