4

condition_variable_any与 a 一起使用时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?
}
4

2 回答 2

6

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

班级condition_variable_any

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

效果:

原子地调用lock.unlock()和阻塞当前线程。当调用this->notify_one()or 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();
}

我希望这可以帮助其他在混合condition_variable_anyrecursive_mutex.

于 2012-08-01T04:19:39.513 回答
1

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

(permit-unlock-depth) allowed_unlock_count表示允许解锁的深度mutex:调用者允许bar解锁互斥锁的allowed_unlock_count次数。此类解锁后,不保证mutex.

(promise-unlock) allowed_unlock_count表示锁定的深度mutex:调用者保证解锁的mutex准确allowed_unlock_count时间将允许其他线程抓取mutex对象。

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

bar取决于(promise-unlock)

// pre: mutex locking depth is allowed_unlock_count
void bar(int allowed_unlock_count)
{
    // mutex locking depth is allowed_unlock_count
    boost::unique_lock<boost::recursive_mutex> lock(mutex);
    // mutex locking depth is allowed_unlock_count+1

    // you might want to turn theses loops
    // into an a special lock object!
    for (int i=0; i<allowed_unlock_count; ++i)
        mutex.unlock();
    // mutex locking depth is 1

    condvar.wait(lock); // other threads can grab mutex

    // mutex locking depth is 1
    for (int i=0; i<allowed_unlock_count; ++i)
        mutex.lock();
    // mutex locking depth is allowed_unlock_count+1
}
// post: mutex locking depth is allowed_unlock_count

被调用函数必须明确允许调用者减少锁定深度。

于 2012-08-17T01:37:21.603 回答