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
れ、所有権レベルが1つ下がります(必ずしもゼロになるとは限りません)。
上記の結論を確認するテストプログラムを作成しました(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(¬ifier);
t1.join();
t2.join();
}
condition_variable_any
これが、とを混合するときに同じジレンマに直面している他の人に役立つことを願っていますrecursive_mutex
。