http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54352
Bug #: 54352 Summary: relaxed data race rules for ~condition_variable_any Classification: Unclassified Product: gcc Version: 4.8.0 Status: UNCONFIRMED Keywords: ABI Severity: normal Priority: P3 Component: libstdc++ AssignedTo: unassig...@gcc.gnu.org ReportedBy: r...@gcc.gnu.org (related to PR 54185, but for condition_variable_any) As Howard pointed out in c++std-lib-32966 this should work: #include <list> #include <mutex> #include <condition_variable> #include <functional> #include <thread> #include <chrono> #include <cassert> #include <algorithm> template <class T> class locked_list { std::mutex mut_; std::list<T> list_; public: typedef typename std::list<T>::iterator iterator; typedef typename T::key key; template <class ...Args> void emplace_back(Args&& ...args) {list_.emplace_back(std::forward<Args>(args)...);} iterator find(const key& k) { std::unique_lock<std::mutex> lk(mut_); while (true) { iterator ep = std::find(list_.begin(), list_.end(), k); if (ep == list_.end()) return ep; if (!ep->busy()) { ep->set_busy(); return ep; } ep->wait(lk); } } void erase(iterator i) { std::lock_guard<std::mutex> _(mut_); assert(i->busy()); i->notify_all(); list_.erase(i); } iterator end() {return list_.end();} }; template <class Key> class elt { Key key_; std::condition_variable_any notbusy_; bool busy_; public: typedef Key key; explicit elt(const Key& k) : key_(k), busy_(false) {} bool busy() const {return busy_;} void set_busy() {busy_ = true;} void unset_busy() {busy_ = false;} template <class Lock> void wait(Lock& lk) {notbusy_.wait(lk);} void notify_all() {notbusy_.notify_all();} bool operator==(const Key& k) const {return key_ == k;} }; void f1(locked_list<elt<int>>& list) { auto i = list.find(1); assert(i != list.end()); std::this_thread::sleep_for(std::chrono::milliseconds(500)); list.erase(i); } void f2(locked_list<elt<int>>& list) { auto i = list.find(1); assert(i == list.end()); } int main() { locked_list<elt<int>> list; list.emplace_back(1); std::thread t1 = std::thread(f1, std::ref(list)); std::this_thread::sleep_for(std::chrono::milliseconds(250)); std::thread t2 = std::thread(f2, std::ref(list)); t1.join(); t2.join(); } This test doesn't actually crash with libstdc++, but valgrind shows it's faulty. Fixing this involves replacing std::condition_variable_any::_M_mutex with a std::shared_ptr<std::mutex>