From 7f426c93a7460029a565712e1665de1b9042ddca Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 4 Jul 2012 22:17:18 +0000 Subject: [PATCH] re PR libstdc++/53830 (condition_variable_any - deadlock issue) PR libstdc++/53830 * include/std/condition_variable (condition_variable_any::wait): Move _Unlock type to class scope. (condition_variable_any::wait_until): Reuse it. * testsuite/30_threads/condition_variable_any/53830.cc: New. From-SVN: r189268 --- libstdc++-v3/ChangeLog | 8 +++ libstdc++-v3/include/std/condition_variable | 46 +++++++------ .../condition_variable_any/53830.cc | 68 +++++++++++++++++++ 3 files changed, 103 insertions(+), 19 deletions(-) create mode 100644 libstdc++-v3/testsuite/30_threads/condition_variable_any/53830.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 47c19c095d8..b22d9071fae 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,11 @@ +2012-07-04 Jonathan Wakely + + PR libstdc++/53830 + * include/std/condition_variable (condition_variable_any::wait): + Move _Unlock type to class scope. + (condition_variable_any::wait_until): Reuse it. + * testsuite/30_threads/condition_variable_any/53830.cc: New. + 2012-07-04 Matthias Klose * testsuite/28_regex/headers/04_header: Remove empty directory. diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable index c4e2080165d..85b50a7eaaf 100644 --- a/libstdc++-v3/include/std/condition_variable +++ b/libstdc++-v3/include/std/condition_variable @@ -176,6 +176,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION condition_variable _M_cond; mutex _M_mutex; + // scoped unlock - unlocks in ctor, re-locks in dtor + template + struct _Unlock + { + explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); } + + ~_Unlock() noexcept(false) + { + if (uncaught_exception()) + __try { _M_lock.lock(); } __catch(...) { } + else + _M_lock.lock(); + } + + _Unlock(const _Unlock&) = delete; + _Unlock& operator=(const _Unlock&) = delete; + + _Lock& _M_lock; + }; + public: condition_variable_any() noexcept; @@ -202,21 +222,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void wait(_Lock& __lock) { - // scoped unlock - unlocks in ctor, re-locks in dtor - struct _Unlock { - explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); } - ~_Unlock() noexcept(false) - { - if (uncaught_exception()) - __try { _M_lock.lock(); } __catch(...) { } - else - _M_lock.lock(); - } - _Lock& _M_lock; - }; - unique_lock __my_lock(_M_mutex); - _Unlock __unlock(__lock); + _Unlock<_Lock> __unlock(__lock); // _M_mutex must be unlocked before re-locking __lock so move // ownership of _M_mutex lock to an object with shorter lifetime. unique_lock __my_lock2(std::move(__my_lock)); @@ -237,11 +244,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION wait_until(_Lock& __lock, const chrono::time_point<_Clock, _Duration>& __atime) { - unique_lock __my_lock(_M_mutex); - __lock.unlock(); - cv_status __status = _M_cond.wait_until(__my_lock, __atime); - __lock.lock(); - return __status; + unique_lock __my_lock(_M_mutex); + _Unlock<_Lock> __unlock(__lock); + // _M_mutex must be unlocked before re-locking __lock so move + // ownership of _M_mutex lock to an object with shorter lifetime. + unique_lock __my_lock2(std::move(__my_lock)); + return _M_cond.wait_until(__my_lock2, __atime); } template. + +// PR libstdc++/53830 +// Test for deadlock in condition_variable_any::wait_for + +#include +#include +#include +#include +#include + +std::mutex mutex; +std::condition_variable_any cv; + +std::atomic barrier(0); + +// waits for data from another thread +void wait_for_data() +{ + std::unique_lock lock(mutex); + barrier = 1; + cv.wait_for(lock, std::chrono::milliseconds(100), []{ return false; }); + // read data +} + +// passes data to waiting thread +void provide_data() +{ + while (barrier == 0) + std::this_thread::yield(); + std::unique_lock lock(mutex); + // pass data + std::this_thread::sleep_for(std::chrono::seconds(1)); + cv.notify_one(); +} + +int main() +{ + std::thread thread1(wait_for_data); + provide_data(); + thread1.join(); + return 0; +} +