Warning, /include/tbb/compat/condition_variable is written in an unsupported language. File is not indexed.
0001 /*
0002 Copyright (c) 2005-2020 Intel Corporation
0003
0004 Licensed under the Apache License, Version 2.0 (the "License");
0005 you may not use this file except in compliance with the License.
0006 You may obtain a copy of the License at
0007
0008 http://www.apache.org/licenses/LICENSE-2.0
0009
0010 Unless required by applicable law or agreed to in writing, software
0011 distributed under the License is distributed on an "AS IS" BASIS,
0012 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013 See the License for the specific language governing permissions and
0014 limitations under the License.
0015 */
0016
0017 #include "../internal/_deprecated_header_message_guard.h"
0018
0019 #if !defined(__TBB_show_deprecation_message_condition_variable_H) && defined(__TBB_show_deprecated_header_message)
0020 #define __TBB_show_deprecation_message_condition_variable_H
0021 #pragma message("TBB Warning: tbb/compat/condition_variable is deprecated. For details, please see Deprecated Features appendix in the TBB reference manual.")
0022 #endif
0023
0024 #if defined(__TBB_show_deprecated_header_message)
0025 #undef __TBB_show_deprecated_header_message
0026 #endif
0027
0028 #ifndef __TBB_condition_variable_H
0029 #define __TBB_condition_variable_H
0030
0031 #define __TBB_condition_variable_H_include_area
0032 #include "../internal/_warning_suppress_enable_notice.h"
0033
0034 #if _WIN32||_WIN64
0035 #include "../machine/windows_api.h"
0036
0037 namespace tbb {
0038 namespace interface5 {
0039 namespace internal {
0040 struct condition_variable_using_event
0041 {
0042 //! Event for blocking waiting threads.
0043 HANDLE event;
0044 //! Protects invariants involving n_waiters, release_count, and epoch.
0045 CRITICAL_SECTION mutex;
0046 //! Number of threads waiting on this condition variable
0047 int n_waiters;
0048 //! Number of threads remaining that should no longer wait on this condition variable.
0049 int release_count;
0050 //! To keep threads from waking up prematurely with earlier signals.
0051 unsigned epoch;
0052 };
0053 }}} // namespace tbb::interface5::internal
0054
0055 #ifndef CONDITION_VARIABLE_INIT
0056 typedef void* CONDITION_VARIABLE;
0057 typedef CONDITION_VARIABLE* PCONDITION_VARIABLE;
0058 #endif
0059
0060 #else /* if not _WIN32||_WIN64 */
0061 #include <errno.h> // some systems need it for ETIMEDOUT
0062 #include <pthread.h>
0063 #if __linux__
0064 #include <ctime>
0065 #else /* generic Unix */
0066 #include <sys/time.h>
0067 #endif
0068 #endif /* _WIN32||_WIN64 */
0069
0070 #include "../tbb_stddef.h"
0071 #include "../mutex.h"
0072 #include "../tbb_thread.h"
0073 #include "../tbb_exception.h"
0074 #include "../tbb_profiling.h"
0075
0076 namespace tbb {
0077
0078 namespace interface5 {
0079
0080 // C++0x standard working draft 30.4.3
0081 // Lock tag types
0082 struct __TBB_DEPRECATED_IN_VERBOSE_MODE defer_lock_t { }; //! do not acquire ownership of the mutex
0083 struct __TBB_DEPRECATED_IN_VERBOSE_MODE try_to_lock_t { }; //! try to acquire ownership of the mutex without blocking
0084 struct __TBB_DEPRECATED_IN_VERBOSE_MODE adopt_lock_t { }; //! assume the calling thread has already
0085 __TBB_DEPRECATED_IN_VERBOSE_MODE const defer_lock_t defer_lock = {};
0086 __TBB_DEPRECATED_IN_VERBOSE_MODE const try_to_lock_t try_to_lock = {};
0087 __TBB_DEPRECATED_IN_VERBOSE_MODE const adopt_lock_t adopt_lock = {};
0088
0089 // C++0x standard working draft 30.4.3.1
0090 //! lock_guard
0091 template<typename M>
0092 class __TBB_DEPRECATED_IN_VERBOSE_MODE lock_guard : tbb::internal::no_copy {
0093 public:
0094 //! mutex type
0095 typedef M mutex_type;
0096
0097 //! Constructor
0098 /** precondition: If mutex_type is not a recursive mutex, the calling thread
0099 does not own the mutex m. */
0100 explicit lock_guard(mutex_type& m) : pm(m) {m.lock();}
0101
0102 //! Adopt_lock constructor
0103 /** precondition: the calling thread owns the mutex m. */
0104 lock_guard(mutex_type& m, adopt_lock_t) : pm(m) {}
0105
0106 //! Destructor
0107 ~lock_guard() { pm.unlock(); }
0108 private:
0109 mutex_type& pm;
0110 };
0111
0112 // C++0x standard working draft 30.4.3.2
0113 //! unique_lock
0114 template<typename M>
0115 class __TBB_DEPRECATED_IN_VERBOSE_MODE unique_lock : tbb::internal::no_copy {
0116 friend class condition_variable;
0117 public:
0118 typedef M mutex_type;
0119
0120 // 30.4.3.2.1 construct/copy/destroy
0121 // NB: Without constructors that take an r-value reference to a unique_lock, the following constructor is of little use.
0122 //! Constructor
0123 /** postcondition: pm==0 && owns==false */
0124 unique_lock() : pm(NULL), owns(false) {}
0125
0126 //! Constructor
0127 /** precondition: if mutex_type is not a recursive mutex, the calling thread
0128 does not own the mutex m. If the precondition is not met, a deadlock occurs.
0129 postcondition: pm==&m and owns==true */
0130 explicit unique_lock(mutex_type& m) : pm(&m) {m.lock(); owns=true;}
0131
0132 //! Defer_lock constructor
0133 /** postcondition: pm==&m and owns==false */
0134 unique_lock(mutex_type& m, defer_lock_t) : pm(&m), owns(false) {}
0135
0136 //! Try_to_lock constructor
0137 /** precondition: if mutex_type is not a recursive mutex, the calling thread
0138 does not own the mutex m. If the precondition is not met, a deadlock occurs.
0139 postcondition: pm==&m and owns==res where res is the value returned by
0140 the call to m.try_lock(). */
0141 unique_lock(mutex_type& m, try_to_lock_t) : pm(&m) {owns = m.try_lock();}
0142
0143 //! Adopt_lock constructor
0144 /** precondition: the calling thread owns the mutex. If it does not, mutex->unlock() would fail.
0145 postcondition: pm==&m and owns==true */
0146 unique_lock(mutex_type& m, adopt_lock_t) : pm(&m), owns(true) {}
0147
0148 //! Timed unique_lock acquisition.
0149 /** To avoid requiring support for namespace chrono, this method deviates from the working draft in that
0150 it uses tbb::tick_count::interval_t to specify the time duration. */
0151 unique_lock(mutex_type& m, const tick_count::interval_t &i) : pm(&m) {owns = try_lock_for( i );}
0152
0153 #if __TBB_CPP11_RVALUE_REF_PRESENT
0154 //! Move constructor
0155 /** postconditions: pm == src_p.pm and owns == src_p.owns (where src_p is the state of src just prior to this
0156 construction), src.pm == 0 and src.owns == false. */
0157 unique_lock(unique_lock && src): pm(NULL), owns(false) {this->swap(src);}
0158
0159 //! Move assignment
0160 /** effects: If owns calls pm->unlock().
0161 Postconditions: pm == src_p.pm and owns == src_p.owns (where src_p is the state of src just prior to this
0162 assignment), src.pm == 0 and src.owns == false. */
0163 unique_lock& operator=(unique_lock && src) {
0164 if (owns)
0165 this->unlock();
0166 pm = NULL;
0167 this->swap(src);
0168 return *this;
0169 }
0170 #endif // __TBB_CPP11_RVALUE_REF_PRESENT
0171
0172 //! Destructor
0173 ~unique_lock() { if( owns ) pm->unlock(); }
0174
0175 // 30.4.3.2.2 locking
0176 //! Lock the mutex and own it.
0177 void lock() {
0178 if( pm ) {
0179 if( !owns ) {
0180 pm->lock();
0181 owns = true;
0182 } else
0183 throw_exception_v4( tbb::internal::eid_possible_deadlock );
0184 } else
0185 throw_exception_v4( tbb::internal::eid_operation_not_permitted );
0186 __TBB_ASSERT( owns, NULL );
0187 }
0188
0189 //! Try to lock the mutex.
0190 /** If successful, note that this lock owns it. Otherwise, set it false. */
0191 bool try_lock() {
0192 if( pm ) {
0193 if( !owns )
0194 owns = pm->try_lock();
0195 else
0196 throw_exception_v4( tbb::internal::eid_possible_deadlock );
0197 } else
0198 throw_exception_v4( tbb::internal::eid_operation_not_permitted );
0199 return owns;
0200 }
0201
0202 //! Try to lock the mutex.
0203 bool try_lock_for( const tick_count::interval_t &i );
0204
0205 //! Unlock the mutex
0206 /** And note that this lock no longer owns it. */
0207 void unlock() {
0208 if( owns ) {
0209 pm->unlock();
0210 owns = false;
0211 } else
0212 throw_exception_v4( tbb::internal::eid_operation_not_permitted );
0213 __TBB_ASSERT( !owns, NULL );
0214 }
0215
0216 // 30.4.3.2.3 modifiers
0217 //! Swap the two unique locks
0218 void swap(unique_lock& u) {
0219 mutex_type* t_pm = u.pm; u.pm = pm; pm = t_pm;
0220 bool t_owns = u.owns; u.owns = owns; owns = t_owns;
0221 }
0222
0223 //! Release control over the mutex.
0224 mutex_type* release() {
0225 mutex_type* o_pm = pm;
0226 pm = NULL;
0227 owns = false;
0228 return o_pm;
0229 }
0230
0231 // 30.4.3.2.4 observers
0232 //! Does this lock own the mutex?
0233 bool owns_lock() const { return owns; }
0234
0235 // TODO: Un-comment 'explicit' when the last non-C++0x compiler support is dropped
0236 //! Does this lock own the mutex?
0237 /*explicit*/ operator bool() const { return owns; }
0238
0239 //! Return the mutex that this lock currently has.
0240 mutex_type* mutex() const { return pm; }
0241
0242 private:
0243 mutex_type* pm;
0244 bool owns;
0245 };
0246
0247 template<typename M>
0248 __TBB_DEPRECATED_IN_VERBOSE_MODE bool unique_lock<M>::try_lock_for( const tick_count::interval_t &i)
0249 {
0250 const int unique_lock_tick = 100; /* microseconds; 0.1 milliseconds */
0251 // the smallest wait-time is 0.1 milliseconds.
0252 bool res = pm->try_lock();
0253 int duration_in_micro;
0254 if( !res && (duration_in_micro=int(i.seconds()*1e6))>unique_lock_tick ) {
0255 tick_count::interval_t i_100( double(unique_lock_tick)/1e6 /* seconds */); // 100 microseconds = 0.1*10E-3
0256 do {
0257 this_tbb_thread::sleep(i_100); // sleep for 100 micro seconds
0258 duration_in_micro -= unique_lock_tick;
0259 res = pm->try_lock();
0260 } while( !res && duration_in_micro>unique_lock_tick );
0261 }
0262 return (owns=res);
0263 }
0264
0265 //! Swap the two unique locks that have the mutexes of same type
0266 template<typename M>
0267 void swap(unique_lock<M>& x, unique_lock<M>& y) { x.swap( y ); }
0268
0269 namespace internal {
0270
0271 #if _WIN32||_WIN64
0272 union condvar_impl_t {
0273 condition_variable_using_event cv_event;
0274 CONDITION_VARIABLE cv_native;
0275 };
0276 void __TBB_EXPORTED_FUNC internal_initialize_condition_variable( condvar_impl_t& cv );
0277 void __TBB_EXPORTED_FUNC internal_destroy_condition_variable( condvar_impl_t& cv );
0278 void __TBB_EXPORTED_FUNC internal_condition_variable_notify_one( condvar_impl_t& cv );
0279 void __TBB_EXPORTED_FUNC internal_condition_variable_notify_all( condvar_impl_t& cv );
0280 bool __TBB_EXPORTED_FUNC internal_condition_variable_wait( condvar_impl_t& cv, mutex* mtx, const tick_count::interval_t* i = NULL );
0281
0282 #else /* if !(_WIN32||_WIN64), i.e., POSIX threads */
0283 typedef pthread_cond_t condvar_impl_t;
0284 #endif
0285
0286 } // namespace internal
0287
0288 //! cv_status
0289 /** C++0x standard working draft 30.5 */
0290 enum cv_status { no_timeout, timeout };
0291
0292 //! condition variable
0293 /** C++0x standard working draft 30.5.1
0294 @ingroup synchronization */
0295 class __TBB_DEPRECATED_IN_VERBOSE_MODE condition_variable : tbb::internal::no_copy {
0296 public:
0297 //! Constructor
0298 condition_variable() {
0299 #if _WIN32||_WIN64
0300 internal_initialize_condition_variable( my_cv );
0301 #else
0302 pthread_cond_init( &my_cv, NULL );
0303 #endif
0304 }
0305
0306 //! Destructor
0307 ~condition_variable() {
0308 //precondition: There shall be no thread blocked on *this.
0309 #if _WIN32||_WIN64
0310 internal_destroy_condition_variable( my_cv );
0311 #else
0312 pthread_cond_destroy( &my_cv );
0313 #endif
0314 }
0315
0316 //! Notify one thread and wake it up
0317 void notify_one() {
0318 #if _WIN32||_WIN64
0319 internal_condition_variable_notify_one( my_cv );
0320 #else
0321 pthread_cond_signal( &my_cv );
0322 #endif
0323 }
0324
0325 //! Notify all threads
0326 void notify_all() {
0327 #if _WIN32||_WIN64
0328 internal_condition_variable_notify_all( my_cv );
0329 #else
0330 pthread_cond_broadcast( &my_cv );
0331 #endif
0332 }
0333
0334 //! Release the mutex associated with the lock and wait on this condition variable
0335 void wait(unique_lock<mutex>& lock);
0336
0337 //! Wait on this condition variable while pred is false
0338 template <class Predicate>
0339 void wait(unique_lock<mutex>& lock, Predicate pred) {
0340 while( !pred() )
0341 wait( lock );
0342 }
0343
0344 //! Timed version of wait()
0345 cv_status wait_for(unique_lock<mutex>& lock, const tick_count::interval_t &i );
0346
0347 //! Timed version of the predicated wait
0348 /** The loop terminates when pred() returns true or when the time duration specified by rel_time (i) has elapsed. */
0349 template<typename Predicate>
0350 bool wait_for(unique_lock<mutex>& lock, const tick_count::interval_t &i, Predicate pred)
0351 {
0352 while( !pred() ) {
0353 cv_status st = wait_for( lock, i );
0354 if( st==timeout )
0355 return pred();
0356 }
0357 return true;
0358 }
0359
0360 // C++0x standard working draft. 30.2.3
0361 typedef internal::condvar_impl_t* native_handle_type;
0362
0363 native_handle_type native_handle() { return (native_handle_type) &my_cv; }
0364
0365 private:
0366 internal::condvar_impl_t my_cv;
0367 };
0368
0369
0370 #if _WIN32||_WIN64
0371 inline void condition_variable::wait( unique_lock<mutex>& lock )
0372 {
0373 __TBB_ASSERT( lock.owns, NULL );
0374 lock.owns = false;
0375 if( !internal_condition_variable_wait( my_cv, lock.mutex() ) ) {
0376 int ec = GetLastError();
0377 // on Windows 7, SleepConditionVariableCS() may return ERROR_TIMEOUT while the doc says it returns WAIT_TIMEOUT
0378 __TBB_ASSERT_EX( ec!=WAIT_TIMEOUT&&ec!=ERROR_TIMEOUT, NULL );
0379 lock.owns = true;
0380 throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
0381 }
0382 lock.owns = true;
0383 }
0384
0385 inline cv_status condition_variable::wait_for( unique_lock<mutex>& lock, const tick_count::interval_t& i )
0386 {
0387 cv_status rc = no_timeout;
0388 __TBB_ASSERT( lock.owns, NULL );
0389 lock.owns = false;
0390 // condvar_wait could be SleepConditionVariableCS (or SleepConditionVariableSRW) or our own pre-vista cond_var_wait()
0391 if( !internal_condition_variable_wait( my_cv, lock.mutex(), &i ) ) {
0392 int ec = GetLastError();
0393 if( ec==WAIT_TIMEOUT || ec==ERROR_TIMEOUT )
0394 rc = timeout;
0395 else {
0396 lock.owns = true;
0397 throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
0398 }
0399 }
0400 lock.owns = true;
0401 return rc;
0402 }
0403
0404 #else /* !(_WIN32||_WIN64) */
0405 inline void condition_variable::wait( unique_lock<mutex>& lock )
0406 {
0407 __TBB_ASSERT( lock.owns, NULL );
0408 lock.owns = false;
0409 if( pthread_cond_wait( &my_cv, lock.mutex()->native_handle() ) ) {
0410 lock.owns = true;
0411 throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
0412 }
0413 // upon successful return, the mutex has been locked and is owned by the calling thread.
0414 lock.owns = true;
0415 }
0416
0417 inline cv_status condition_variable::wait_for( unique_lock<mutex>& lock, const tick_count::interval_t& i )
0418 {
0419 #if __linux__
0420 struct timespec req;
0421 double sec = i.seconds();
0422 clock_gettime( CLOCK_REALTIME, &req );
0423 req.tv_sec += static_cast<long>(sec);
0424 req.tv_nsec += static_cast<long>( (sec - static_cast<long>(sec))*1e9 );
0425 #else /* generic Unix */
0426 struct timeval tv;
0427 struct timespec req;
0428 double sec = i.seconds();
0429 int status = gettimeofday(&tv, NULL);
0430 __TBB_ASSERT_EX( status==0, "gettimeofday failed" );
0431 req.tv_sec = tv.tv_sec + static_cast<long>(sec);
0432 req.tv_nsec = tv.tv_usec*1000 + static_cast<long>( (sec - static_cast<long>(sec))*1e9 );
0433 #endif /*(choice of OS) */
0434 if( req.tv_nsec>=1e9 ) {
0435 req.tv_sec += 1;
0436 req.tv_nsec -= static_cast<long int>(1e9);
0437 }
0438 __TBB_ASSERT( 0<=req.tv_nsec && req.tv_nsec<1e9, NULL );
0439
0440 int ec;
0441 cv_status rc = no_timeout;
0442 __TBB_ASSERT( lock.owns, NULL );
0443 lock.owns = false;
0444 if( ( ec=pthread_cond_timedwait( &my_cv, lock.mutex()->native_handle(), &req ) ) ) {
0445 if( ec==ETIMEDOUT )
0446 rc = timeout;
0447 else {
0448 __TBB_ASSERT( lock.try_lock()==false, NULL );
0449 lock.owns = true;
0450 throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
0451 }
0452 }
0453 lock.owns = true;
0454 return rc;
0455 }
0456 #endif /* !(_WIN32||_WIN64) */
0457
0458 } // namespace interface5
0459
0460 __TBB_DEFINE_PROFILING_SET_NAME(interface5::condition_variable)
0461
0462 } // namespace tbb
0463
0464 #if TBB_IMPLEMENT_CPP0X
0465
0466 namespace std {
0467
0468 using tbb::interface5::defer_lock_t;
0469 using tbb::interface5::try_to_lock_t;
0470 using tbb::interface5::adopt_lock_t;
0471 using tbb::interface5::defer_lock;
0472 using tbb::interface5::try_to_lock;
0473 using tbb::interface5::adopt_lock;
0474 using tbb::interface5::lock_guard;
0475 using tbb::interface5::unique_lock;
0476 using tbb::interface5::swap; /* this is for void std::swap(unique_lock<M>&,unique_lock<M>&) */
0477 using tbb::interface5::condition_variable;
0478 using tbb::interface5::cv_status;
0479 using tbb::interface5::timeout;
0480 using tbb::interface5::no_timeout;
0481
0482 } // namespace std
0483
0484 #endif /* TBB_IMPLEMENT_CPP0X */
0485
0486 #include "../internal/_warning_suppress_disable_notice.h"
0487 #undef __TBB_condition_variable_H_include_area
0488
0489 #endif /* __TBB_condition_variable_H */