与recursive_mutex一起使用时condition_variable_any的行为?

时间:2012-08-01 03:23:14

标签: c++ multithreading c++11 boost recursive-mutex

condition_variable_anyrecursive_mutex一起使用时,在recursive_mutex等待时,condition_variable_any::wait 通常可以从其他线程获取吗?我对Boost和C ++ 11的实现感兴趣。

这是我主要关注的用例:

void bar();

boost::recursive_mutex mutex;
boost::condition_variable_any condvar;

void foo()
{
    boost::lock_guard<boost::recursive_mutex> lock(mutex);
    // Ownership level is now one

    bar();
}

void bar()
{
    boost::unique_lock<boost::recursive_mutex> lock(mutex);
    // Ownership level is now two

    condvar.wait(lock);
   // Does this fully release the recursive mutex,
   // so that other threads may acquire it while we're waiting?
   // Will the recursive_mutex ownership level
   // be restored to two after waiting?
}

2 个答案:

答案 0 :(得分:5)

通过对Boost文档的严格解释,我得出结论,condition_variable_any::wait 通常不会导致导致其他线程在等待通知时可以获取recursive_mutex

  

班级condition_variable_any

     

<强> template<typename lock_type> void wait(lock_type& lock)

     

效果:

     

原子调用lock.unlock()并阻止当​​前线程。通过调用this->notify_one()或通知时,该线程将取消阻止   this->notify_all(),或虚假地。线程解除阻塞时(for   无论什么原因),通过调用lock.lock()重新获取锁定   在等待调用之前返回。锁也被重新获取   如果函数以异常退出,则调用lock.lock()

因此condvar.wait(lock)会调用lock.unlock,而mutex.unlock会调用#include <iostream> #define USE_BOOST 1 #if USE_BOOST #include <boost/chrono.hpp> #include <boost/thread.hpp> #include <boost/thread/condition_variable.hpp> #include <boost/thread/locks.hpp> #include <boost/thread/recursive_mutex.hpp> namespace lib = boost; #else #include <chrono> #include <thread> #include <condition_variable> #include <mutex> namespace lib = std; #endif void bar(); lib::recursive_mutex mutex; lib::condition_variable_any condvar; int value = 0; void foo() { std::cout << "foo()\n"; lib::lock_guard<lib::recursive_mutex> lock(mutex); // Ownership level is now one bar(); } void bar() { std::cout << "bar()\n"; lib::unique_lock<lib::recursive_mutex> lock(mutex); // Ownership level is now two condvar.wait(lock); // Does this fully release the recursive mutex? std::cout << "value = " << value << "\n"; } void notifier() { std::cout << "notifier()\n"; lib::this_thread::sleep_for(lib::chrono::seconds(3)); std::cout << "after sleep\n"; // --- Program deadlocks here --- lib::lock_guard<lib::recursive_mutex> lock(mutex); value = 42; std::cout << "before notify_one\n"; condvar.notify_one(); } int main() { lib::thread t1(&foo); // This results in deadlock // lib::thread t1(&bar); // This doesn't result in deadlock lib::thread t2(&notifier); t1.join(); t2.join(); } ,这会将所有权级别降低一级(并且不一定降低到零)。


我写了一个测试程序,证实了我的上述结论(对于Boost和C ++ 11):

condition_variable_any

我希望在混合recursive_mutex和{{1}}时,这可以帮助其他任何面临同样困境的人。

答案 1 :(得分:1)

您可以通过向每个对allowed_unlock_count对象进行操作的函数添加参数mutex来修复此设计。有关allowed_unlock_count的保证有两种类型:

(允许解锁深度) allowed_unlock_count表示mutex允许解锁的深度:来电者允许bar解锁互斥锁{{1}时间。解锁后,不保证allowed_unlock_count的状态。

(承诺解锁) mutex表示allowed_unlock_count的锁定深度:来电者保证mutex完全解锁mutex次允许其他线程获取allowed_unlock_count对象。

这些保证是功能的前后条件

此处mutex取决于(承诺解锁)

bar

调用函数必须显式允许调用者减少锁定深度。