[Boost-bugs] [Boost C++ Libraries] #7334: Fix bug concerning condition_variable_any reported in [c++std-lib-32966]

Subject: [Boost-bugs] [Boost C++ Libraries] #7334: Fix bug concerning condition_variable_any reported in [c++std-lib-32966]
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2012-09-06 04:19:24


#7334: Fix bug concerning condition_variable_any reported in [c++std-lib-32966]
------------------------------+---------------------------------------------
 Reporter: viboes | Owner: anthonyw
     Type: Bugs | Status: new
Milestone: To Be Determined | Component: thread
  Version: Boost 1.51.0 | Severity: Problem
 Keywords: |
------------------------------+---------------------------------------------
 the following is ok:


 {{{
   Thread A Thread B
    ... lk.lock()
    ... cv.wait(lk)
   lk.lock() ...
   cv.notify_one() ...
   cv.~condition_variable_any() ...
   lk.unlock() ...
     ... finally exits cv.wait // ok, not a data
 race
 }}}

 Below is a complete C++11 HelloWorld that is a simple translation of the
 example in the POSIX pthread_cond_destroy spec. It should run and not
 crash or assert:


 {{{
 #include <list>
 #include <mutex>
 #include <condition_variable>
 #include <functional>
 #include <thread>
 #include <chrono>
 #include <cassert>

 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();
 }

 }}}

 If we substitute in boost::condition_variable_any for
 std::condition_variable_any for the notbusy_ data member of class elt, we
 get:


 {{{
 Assertion failed: (!pthread_mutex_unlock(m)), function
 ~interruption_checker, file /Users/hhinnant/Development/boost-dev/boost-
 trunk/boost/thread/pthread/thread_data.hpp, line 171.
 Abort trap: 6
 }}}

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/7334>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:10 UTC