C++11標準ライブラリを用いた再帰ミューテックスrecursive_mutexクラスの内部実装 3パターン。標準ライブラリが提供するstd::recursive_mutexの再実装。
各実装で利用している同期プリミティブ
- #1:
std::mutex+std::condition_variable - #2: 2個の
std::mutex - #3:
std::atomic+std::mutex
メモ:
std::thread::idクラスのコンストラクタが非constexprなため、recursive_mutexクラスのコンストラクタをconstexprにできず。(標準ライブラリ提供のstd::recursive_mutexも非constexprコンストラクタを持つ→id:yohhoy:20120621)#3は全部全てstd::memory_order_relaxedでも良いような?relaxed操作でも標準ライブラリ相当の動作仕様を満たす(→id:yohhoy:20120404)- lock/try_lockメンバ関数における
mtx_ロック外でのowner_.load(relaxed)は、atomic変数であるためdata race free。 - このとき自スレッドがロック獲得中であれば、"sequenced before" 関係により自スレッドが書込んだ自スレッドIDを観測してtrue側へ分岐する。それ以外であれば、"sequenced before" 関係により自スレッドunlockで書込んだ値
thread::id()、または "visible sequence of side effects" により他スレッドが書込んだ値を観測してfalse側へ分岐する。このとき他スレッドID(他スレッドがロック獲得中)と観測できなかったとしても、続くmtx_.lock操作でブロックされるためrecursive_mutex動作仕様を満たす。 - unlockメンバ関数では
owner_.store(relaxed)であっても、続くmtx_.unlockがreleaseセマンティクスを持つため、値thread::id()代入結果は他スレッドから可視となる。(直接的に上記動作へは寄与しない)
- lock/try_lockメンバ関数における