
On Nov 15, 2007, at 10:24 AM, Alexander Terekhov wrote:
Howard Hinnant wrote:
On Nov 15, 2007, at 7:02 AM, Alexander Terekhov wrote:
http://svn.boost.org/svn/boost/trunk/boost/thread/pthread/condition_variable...
That condition_variable_any wrapper doesn't ensure same destruction safety of condition varaible as POSIX pthread_cond_t. That's not good.
Thanks for this observation Alexander. Do you have a recommendation for fixing it? The best I'm coming up with at the moment is to keep a count of waiters as member data and have ~condition_variable_any() wait until the count drops to zero.
Or simply use shared_ptr<pthread_mutex_t> for internal_mutex. Peter will like that. :-)
:-) Thanks Alexander. I've been debugging this beast for years now. Maybe, just maybe, it's debugged now. :-) struct __lock_external { template <class _Lock> void operator()(_Lock* __m) {__m->lock();} }; class condition_variable_any { condition_variable cv_; shared_ptr<mutex> mut_; public: condition_variable_any() : mut_(new mutex) {} // ~condition_variable_any() = default; // condition_variable_any(const condition_variable_any&) = delete; // condition_variable_any& operator=(const condition_variable_any&) = delete; void notify_one(); void notify_all(); template <class Lock> void wait(Lock& lock); template <class Lock, class Predicate> void wait(Lock& lock, Predicate pred); template <class Lock> bool timed_wait(Lock& lock, const system_time& abs_time); template <class Lock, class Predicate> bool timed_wait(Lock& lock, const system_time& abs_time, Predicate pred); template <class Lock, class Duration, class Predicate> bool timed_wait(Lock& lock, const Duration& rel_time, Predicate pred); }; inline void condition_variable_any::notify_one() { lock_guard<mutex> _(*mut_); cv_.notify_one(); } inline void condition_variable_any::notify_all() { lock_guard<mutex> _(*mut_); cv_.notify_all(); } template <class Lock> void condition_variable_any::wait(Lock& lock) { shared_ptr<mutex> mut = mut_; unique_lock<mutex> lk(*mut); lock.unlock(); unique_ptr<Lock, __lock_external> external_guard(&lock); lock_guard<unique_lock<mutex>> internal_guard(lk, adopt_lock); cv_.wait(lk); } // mut_.unlock(), lock.lock() template <class Lock, class Predicate> inline void condition_variable_any::wait(Lock& lock, Predicate pred) { while (!pred()) wait(lock); } template <class Lock> bool condition_variable_any::timed_wait(Lock& lock, const system_time& abs_time) { shared_ptr<mutex> mut = mut_; unique_lock<mutex> lk(*mut); lock.unlock(); unique_ptr<Lock, __lock_external> external_guard(&lock); lock_guard<unique_lock<mutex>> internal_guard(lk, adopt_lock); return cv_.timed_wait(lk, abs_time); } // mut_.unlock(), lock.lock() template <class Lock, class Predicate> inline bool condition_variable_any::timed_wait(Lock& lock, const system_time& abs_time, Predicate pred) { while (!pred()) if (!timed_wait(lock, abs_time)) return pred(); return true; } template <class Lock, class Duration, class Predicate> inline bool condition_variable_any::timed_wait(Lock& lock, const Duration& rel_time, Predicate pred) { return timed_wait(lock, get_system_time() + rel_time, std::move(pred)); }
BTW, condition_variable_any's (timed_}wait() above doesn't seem to m.lock() in the case of threads cancel (interruption). That doesn't match POSIX (and condition_variable thin wrapper) behavior.
<nod> -Howard