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

Emi*_*ier 4 c++ multithreading boost c++11 recursive-mutex

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

这是我主要关注的用例:

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?
}
Run Code Online (Sandbox Code Playgroud)

Emi*_*ier 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()或虚假地通知时,线程将解除阻塞.当线程被解除阻塞(无论出于何种原因)时,通过lock.lock() 在等待调用返回之前调用来重新获取锁.lock.lock()如果函数以异常退出,则还可以通过调用来重新获取锁.

所以condvar.wait(lock)将调用lock.unlock,反过来调用mutex.unlock,它将所有权级别降低一(并且不一定降低到零).


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

#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();
}
Run Code Online (Sandbox Code Playgroud)

我希望这可以帮助别人搅拌时面临着同样的困境condition_variable_anyrecursive_mutex.

  • +1 C++ 11规范与boost文档非常相似.这是在C++草案(当时)之后增强的罕见情况,而不是反之亦然.`condition_variable_any`在http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2447.htm中提出,当时的规范要求递归锁的锁定计数为1在进入等待.具体措辞已经改变,但意图没有改变.然后提升然后捡起来. (3认同)