将condition_variable_any
与recursive_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?
}
答案 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(¬ifier);
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
调用函数必须显式允许调用者减少锁定深度。