C++11標準ライブラリ提供の ミューテックス および ロックオブジェクト とロック状態の取得について。
std::mutex
などのミューテックス型は、自スレッドでロック獲得済みかを問合せるインタフェースを提供しない。代わりにstd::unique_lock
クラステンプレートのowns_lock
メンバ関数を用いれば現在のロック状態を確認できる。*1
#include <mutex> #include <cassert> std::mutex m1, m2; { std::unique_lock<decltype(m1)> lk1(m1); std::unique_lock<decltype(m2)> lk2(m2, std::defer_lock); assert( lk1.owns_lock() ); // ロック獲得済み assert( !lk2.owns_lock() ); // 未ロック状態 }
下記コードのように、自スレッドでロック獲得済みの非再帰的なミューテックスstd::mutex
やstd::timed_mutex
に対し、try_lock
メンバ関数などを “ロック状態問合せ” を意図して利用すると未定義動作(undefined behavior)を引き起こす。タイムアウト付きロック獲得try_lock_for
/until
であっても同様に未定義動作。*2
std::mutex m; { m.lock(); // mのロック獲得済み assert( !m.try_lock() ); // NG: 未定義動作! m.unlock(); }
メモ:そもそも直接ミューテックスオブジェクトのlock
/unlock
を呼び出すのではなく、通常はロックオブジェクト経由でミューテックスのロック獲得/解放操作を行うべき。またロックオブジェクトはScoped Lockイディオムを実現するものであり、ロック状態は “ロックオブジェクト変数のスコープ” として既に表現されていると解釈される。このとき、実行時に確認したロック状態に依存して処理内容を切替えというユースケースは希少(or 設計が不適切)だと思う。実行パスとして複数回ロック獲得操作が起こり得るなら、設計段階で再帰ロック可能なミューテックスを採用すればよい。
関連URL