2 Copyright 2005-2010 Intel Corporation. All Rights Reserved.
4 This file is part of Threading Building Blocks.
6 Threading Building Blocks is free software; you can redistribute it
7 and/or modify it under the terms of the GNU General Public License
8 version 2 as published by the Free Software Foundation.
10 Threading Building Blocks is distributed in the hope that it will be
11 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with Threading Building Blocks; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 As a special exception, you may use this file as part of a free software
20 library without restriction. Specifically, if other files instantiate
21 templates or use macros or inline functions from this file, or you compile
22 this file and link it with other files to produce an executable, this
23 file does not by itself cause the resulting executable to be covered by
24 the GNU General Public License. This exception does not however
25 invalidate any other reasons why the executable file might be covered by
26 the GNU General Public License.
29 #ifndef __TBB_condition_variable_H
30 #define __TBB_condition_variable_H
36 namespace interface5 {
38 struct condition_variable_using_event
40 //! Event for blocking waiting threads.
42 //! Protects invariants involving n_waiters, release_count, and epoch.
43 CRITICAL_SECTION mutex;
44 //! Number of threads waiting on this condition variable
46 //! Number of threads remaining that should no longer wait on this condition variable.
48 //! To keep threads from waking up prematurely with earlier signals.
51 }}} // namespace tbb::interface5::internal
53 #ifndef CONDITION_VARIABLE_INIT
54 typedef void* CONDITION_VARIABLE;
55 typedef CONDITION_VARIABLE* PCONDITION_VARIABLE;
58 #else /* if not _WIN32||_WIN64 */
60 #endif /* _WIN32||_WIN64 */
62 #include "../tbb_stddef.h"
64 #include "../tbb_thread.h"
65 #include "../tbb_exception.h"
66 #include "../tbb_profiling.h"
70 namespace interface5 {
72 // C++0x standard working draft 30.4.3
74 struct defer_lock_t { }; //! do not acquire ownership of the mutex
75 struct try_to_lock_t { }; //! try to acquire ownership of the mutex without blocking
76 struct adopt_lock_t { }; //! assume the calling thread has already
77 const defer_lock_t defer_lock = {};
78 const try_to_lock_t try_to_lock = {};
79 const adopt_lock_t adopt_lock = {};
81 // C++0x standard working draft 30.4.3.1
84 class lock_guard : tbb::internal::no_copy {
90 /** precondition: If mutex_type is not a recursive mutex, the calling thread
91 does not own the mutex m. */
92 explicit lock_guard(mutex_type& m) : pm(m) {m.lock();}
94 //! Adopt_lock constructor
95 /** precondition: the calling thread owns the mutex m. */
96 lock_guard(mutex_type& m, adopt_lock_t) : pm(m) {}
99 ~lock_guard() { pm.unlock(); }
104 // C++0x standard working draft 30.4.3.2
107 class unique_lock : tbb::internal::no_copy {
108 friend class condition_variable;
110 typedef M mutex_type;
112 // 30.4.3.2.1 construct/copy/destroy
113 // NB: Without constructors that take an r-value reference to a unique_lock, the following constructor is of little use.
115 /** postcondition: pm==0 && owns==false */
116 unique_lock() : pm(NULL), owns(false) {}
119 /** precondition: if mutex_type is not a recursive mutex, the calling thread
120 does not own the mutex m. If the precondition is not met, a deadlock occurs.
121 postcondition: pm==&m and owns==true */
122 explicit unique_lock(mutex_type& m) : pm(&m) {m.lock(); owns=true;}
124 //! Defer_lock constructor
125 /** postcondition: pm==&m and owns==false */
126 unique_lock(mutex_type& m, defer_lock_t) : pm(&m), owns(false) {}
128 //! Try_to_lock constructor
129 /** precondition: if mutex_type is not a recursive mutex, the calling thread
130 does not own the mutex m. If the precondition is not met, a deadlock occurs.
131 postcondition: pm==&m and owns==res where res is the value returned by
132 the call to m.try_lock(). */
133 unique_lock(mutex_type& m, try_to_lock_t) : pm(&m) {owns = m.try_lock();}
135 //! Adopt_lock constructor
136 /** precondition: the calling thread owns the mutex. If it does not, mutex->unlock() would fail.
137 postcondition: pm==&m and owns==true */
138 unique_lock(mutex_type& m, adopt_lock_t) : pm(&m), owns(true) {}
140 //! Timed unique_lock acquisition.
141 /** To avoid requiring support for namespace chrono, this method deviates from the working draft in that
142 it uses tbb::tick_count::interval_t to specify the time duration. */
143 unique_lock(mutex_type& m, const tick_count::interval_t &i) : pm(&m) {owns = try_lock_for( i );}
146 ~unique_lock() { if( owns ) pm->unlock(); }
148 // 30.4.3.2.2 locking
149 //! Lock the mutex and own it.
156 throw_exception_v4( tbb::internal::eid_possible_deadlock );
158 throw_exception_v4( tbb::internal::eid_operation_not_permitted );
159 __TBB_ASSERT( owns, NULL );
162 //! Try to lock the mutex.
163 /** If successful, note that this lock owns it. Otherwise, set it false. */
167 owns = pm->try_lock();
169 throw_exception_v4( tbb::internal::eid_possible_deadlock );
171 throw_exception_v4( tbb::internal::eid_operation_not_permitted );
175 //! Try to lock the mutex.
176 bool try_lock_for( const tick_count::interval_t &i );
179 /** And note that this lock no longer owns it. */
185 throw_exception_v4( tbb::internal::eid_operation_not_permitted );
186 __TBB_ASSERT( !owns, NULL );
189 // 30.4.3.2.3 modifiers
190 //! Swap the two unique locks
191 void swap(unique_lock& u) {
192 mutex_type* t_pm = u.pm; u.pm = pm; pm = t_pm;
193 bool t_owns = u.owns; u.owns = owns; owns = t_owns;
196 //! Release control over the mutex.
197 mutex_type* release() {
198 mutex_type* o_pm = pm;
204 // 30.4.3.2.4 observers
205 //! Does this lock own the mutex?
206 bool owns_lock() const { return owns; }
208 //! Does this lock own the mutex?
209 /*explicit*/ operator bool() const { return owns; }
211 //! Return the mutex that this lock currently has.
212 mutex_type* mutex() const { return pm; }
220 bool unique_lock<M>::try_lock_for( const tick_count::interval_t &i)
222 const int unique_lock_tick = 100; /* microseconds; 0.1 milliseconds */
223 // the smallest wait-time is 0.1 milliseconds.
224 bool res = pm->try_lock();
225 int duration_in_micro;
226 if( !res && (duration_in_micro=int(i.seconds()*1e6))>unique_lock_tick ) {
227 tick_count::interval_t i_100( double(unique_lock_tick)/1e6 /* seconds */); // 100 microseconds = 0.1*10E-3
229 this_tbb_thread::sleep(i_100); // sleep for 100 micro seconds
230 duration_in_micro -= unique_lock_tick;
231 res = pm->try_lock();
232 } while( !res && duration_in_micro>unique_lock_tick );
237 //! Swap the two unique locks that have the mutexes of same type
239 void swap(unique_lock<M>& x, unique_lock<M>& y) { x.swap( y ); }
244 union condvar_impl_t {
245 condition_variable_using_event cv_event;
246 CONDITION_VARIABLE cv_native;
249 void __TBB_EXPORTED_FUNC internal_initialize_condition_variable( condvar_impl_t& cv );
250 void __TBB_EXPORTED_FUNC internal_destroy_condition_variable( condvar_impl_t& cv );
251 void __TBB_EXPORTED_FUNC internal_condition_variable_notify_one( condvar_impl_t& cv );
252 void __TBB_EXPORTED_FUNC internal_condition_variable_notify_all( condvar_impl_t& cv );
253 bool __TBB_EXPORTED_FUNC internal_condition_variable_wait( condvar_impl_t& cv, mutex* mtx, const tick_count::interval_t* i = NULL );
254 #else /* if !(_WIN32||_WIN64), i.e., POSIX threads */
255 typedef pthread_cond_t condvar_impl_t;
258 } // namespace internal
261 /** C++0x standard working draft 30.5 */
262 enum cv_status { no_timeout, timeout };
264 //! condition variable
265 /** C++0x standard working draft 30.5.1
266 @ingroup synchronization */
267 class condition_variable : tbb::internal::no_copy {
270 condition_variable() {
272 internal_initialize_condition_variable( my_cv );
274 pthread_cond_init( &my_cv, NULL );
279 ~condition_variable() {
280 //precondition: There shall be no thread blocked on *this.
282 internal_destroy_condition_variable( my_cv );
284 pthread_cond_destroy( &my_cv );
288 //! Notify one thread and wake it up
291 internal_condition_variable_notify_one( my_cv );
293 pthread_cond_signal( &my_cv );
297 //! Notify all threads
300 internal_condition_variable_notify_all( my_cv );
302 pthread_cond_broadcast( &my_cv );
306 //! Release the mutex associated with the lock and wait on this condition variable
307 void wait(unique_lock<mutex>& lock);
309 //! Wait on this condition variable while pred is false
310 template <class Predicate>
311 void wait(unique_lock<mutex>& lock, Predicate pred) {
316 //! Timed version of wait()
317 cv_status wait_for(unique_lock<mutex>& lock, const tick_count::interval_t &i );
319 //! Timed version of the predicated wait
320 /** The loop terminates when pred() returns true or when the time duration specified by rel_time (i) has elapsed. */
321 template<typename Predicate>
322 bool wait_for(unique_lock<mutex>& lock, const tick_count::interval_t &i, Predicate pred)
325 cv_status st = wait_for( lock, i );
332 // C++0x standard working draft. 30.2.3
333 typedef internal::condvar_impl_t* native_handle_type;
335 native_handle_type native_handle() { return (native_handle_type) &my_cv; }
338 internal::condvar_impl_t my_cv;
343 inline void condition_variable::wait( unique_lock<mutex>& lock )
345 __TBB_ASSERT( lock.owns, NULL );
347 if( !internal_condition_variable_wait( my_cv, lock.mutex() ) ) {
348 int ec = GetLastError();
349 // on Windows 7, SleepConditionVariableCS() may return ERROR_TIMEOUT while the doc says it returns WAIT_TIMEOUT
350 __TBB_ASSERT_EX( ec!=WAIT_TIMEOUT&&ec!=ERROR_TIMEOUT, NULL );
352 throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
357 inline cv_status condition_variable::wait_for( unique_lock<mutex>& lock, const tick_count::interval_t& i )
359 cv_status rc = no_timeout;
360 __TBB_ASSERT( lock.owns, NULL );
362 // condvar_wait could be SleepConditionVariableCS (or SleepConditionVariableSRW) or our own pre-vista cond_var_wait()
363 if( !internal_condition_variable_wait( my_cv, lock.mutex(), &i ) ) {
364 int ec = GetLastError();
365 if( ec==WAIT_TIMEOUT || ec==ERROR_TIMEOUT )
369 throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
378 #else /* generic Unix */
379 #include <sys/time.h>
383 inline void condition_variable::wait( unique_lock<mutex>& lock )
385 __TBB_ASSERT( lock.owns, NULL );
387 if( pthread_cond_wait( &my_cv, lock.mutex()->native_handle() ) ) {
389 throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
391 // upon successful return, the mutex has been locked and is owned by the calling thread.
395 inline cv_status condition_variable::wait_for( unique_lock<mutex>& lock, const tick_count::interval_t& i )
399 double sec = i.seconds();
400 clock_gettime( CLOCK_REALTIME, &req );
401 req.tv_sec += static_cast<long>(sec);
402 req.tv_nsec += static_cast<long>( (sec - static_cast<long>(sec))*1e9 );
403 #else /* generic Unix */
406 double sec = i.seconds();
407 int status = gettimeofday(&tv, NULL);
408 __TBB_ASSERT_EX( status==0, "gettimeofday failed" );
409 req.tv_sec = tv.tv_sec + static_cast<long>(sec);
410 req.tv_nsec = tv.tv_usec*1000 + static_cast<long>( (sec - static_cast<long>(sec))*1e9 );
411 #endif /*(choice of OS) */
414 cv_status rc = no_timeout;
415 __TBB_ASSERT( lock.owns, NULL );
417 if( ( ec=pthread_cond_timedwait( &my_cv, lock.mutex()->native_handle(), &req ) ) ) {
421 __TBB_ASSERT( lock.try_lock()==false, NULL );
423 throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
429 #endif /* !(_WIN32||_WIN64) */
431 } // namespace interface5
433 __TBB_DEFINE_PROFILING_SET_NAME(interface5::condition_variable)
437 #if TBB_IMPLEMENT_CPP0X
441 using tbb::interface5::defer_lock_t;
442 using tbb::interface5::try_to_lock_t;
443 using tbb::interface5::adopt_lock_t;
444 using tbb::interface5::defer_lock;
445 using tbb::interface5::try_to_lock;
446 using tbb::interface5::adopt_lock;
447 using tbb::interface5::lock_guard;
448 using tbb::interface5::unique_lock;
449 using tbb::interface5::swap; /* this is for void std::swap(unique_lock<M>&,unique_lock<M>&) */
450 using tbb::interface5::condition_variable;
451 using tbb::interface5::cv_status;
452 using tbb::interface5::timeout;
453 using tbb::interface5::no_timeout;
457 #endif /* TBB_IMPLEMENT_CPP0X */
459 #endif /* __TBB_condition_variable_H */