Re: [Boost-users] Race in boost::condition_variable::wait
Not sure I understand your question. Unless I'm missing something, the guard in condition_variable::wait does not release the mutex, it is simply there to ensure that it is reacquired on exit. The mutex is released by pthread_cond_wait (atomically with the wait on the condition). Éric Malenfant Le 2015-12-22 8:30 PM, "Chris Stankevitz" <chrisstankevitz@gmail.com> a écrit : Hi, Regarding boost::condition_variable::wait (listed below with an obvious modification), It seems to me that there is a race condition because the following operations are not atomic: 1) unlocking of "m" 2) waiting on "cond". Can someone explain to me why boost::condition_variable::wait is not racing the user code in the example below? Thank you, Chris === inline void condition_variable::wait(unique_lock<mutex>& m) { int res=0; { thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard; detail::interruption_checker check_for_interruption(&internal_mutex,&cond); guard.activate(m); #ifdef ENCOURAGE_DEADLOCK boost::this_thread::sleep_for(boost::chrono::seconds(100)); #endif do { res = pthread_cond_wait(&cond,&internal_mutex); } while (res == EINTR); } } === #define ENCOURAGE_DEADLOCK #include <boost/thread.hpp> int main() { boost::mutex Mutex; boost::condition_variable Condition; bool Quit = false; boost::thread Thread([&] { boost::unique_lock<boost::mutex> Lock(Mutex); while (!Quit) { Condition.wait(Lock); } }); boost::this_thread::sleep_for(boost::chrono::seconds(1)); boost::lock_guard<boost::mutex> Lock(Mutex); Quit = true; Condition.notify_all(); return 0; } _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On Wed, Dec 23, 2015 at 7:44 AM, Éric Malenfant <eric.malenfant@gmail.com> wrote:
Unless I'm missing something, the guard in condition_variable::wait does not release the mutex, it is simply there to ensure that it is reacquired on exit. The mutex is released by pthread_cond_wait (atomically with the wait on the condition).
Eric, Thank you for your reply. I believe you are incorrect that the guard only reacquires (and does not release) the mutex. The line "guard.activate(m);" indeed releases the user mutex before pthread_cond_wait (see below). You are correct that pthread_cond_wait atomically releases the mutex -- but it is releasing the internal boost mutex, not the "external" user mutex which has already been released by the guard. I assume that I am missing something, but I cannot figure out what it is. Chris === template<typename MutexType> struct lock_on_exit { MutexType* m; lock_on_exit(): m(0) {} void activate(MutexType& m_) { m_.unlock(); m=&m_; } ~lock_on_exit() { if(m) { m->lock(); } } };
You're right and I was doubly wrong: the guard locks the mutex on activate() and I totally missed the point about the "internal vs external mutex". (Note to self: don't try to read code on your tiny smartphone screen) However, I still don't understand your question. The thread releases the external mutex while holding the internal, and notify_all acquires the internal before notifying the condition. Éric Malenfant Le 2015-12-23 12:19 PM, "Chris Stankevitz" <chrisstankevitz@gmail.com> a écrit :
On Wed, Dec 23, 2015 at 7:44 AM, Éric Malenfant <eric.malenfant@gmail.com> wrote:
Unless I'm missing something, the guard in condition_variable::wait does not release the mutex, it is simply there to ensure that it is reacquired on exit. The mutex is released by pthread_cond_wait (atomically with the wait on the condition).
Eric,
Thank you for your reply.
I believe you are incorrect that the guard only reacquires (and does not release) the mutex. The line "guard.activate(m);" indeed releases the user mutex before pthread_cond_wait (see below).
You are correct that pthread_cond_wait atomically releases the mutex -- but it is releasing the internal boost mutex, not the "external" user mutex which has already been released by the guard.
I assume that I am missing something, but I cannot figure out what it is.
Chris
===
template<typename MutexType> struct lock_on_exit { MutexType* m;
lock_on_exit(): m(0) {}
void activate(MutexType& m_) { m_.unlock(); m=&m_; } ~lock_on_exit() { if(m) { m->lock(); } } }; _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On Wed, Dec 23, 2015 at 3:02 PM, Éric Malenfant <eric.malenfant@gmail.com> wrote:
However, I still don't understand your question. The thread releases the external mutex while holding the internal, and notify_all acquires the internal before notifying the condition.
Eric, Thank you again. I did not understand that boost::condition_variable::notify locked the internal mutex. I now see how it all works and that indeed there is no race. Chris
participants (2)
-
Chris Stankevitz
-
Éric Malenfant