条件変数(condition variable)同期プリミティブの利用に関して、不適切な単一スレッド通知notify_one
の使用によるデッドロック(dead lock)発生についてメモ。(条件変数 Step-by-Step入門のおまけ記事)
スレッド間の非同期データ送受信機構mt_slot<T>
として*1、C++11標準ライブラリによる下記実装を考える。
- スレッド間で
T
型の単一データを保持/取得するクラス。put
で設定値を保持し、get
で値を取得する。 - データ未保持状態で
get
を呼び出すと、別スレッドがput
するまでブロッキングする。 - データ保持状態で
put
を呼び出すと、別スレッドがget
するまでブロッキングする。
// mt_slot実装 #include <utility> #include <mutex> #include <condition_variable> template<typename T> class mt_slot { T slot_; bool hold_ = false; std::mutex mtx_; std::condition_variable cv_; typedef std::unique_lock<std::mutex> Lock; public: void put(T data) { Lock lk(mtx_); while (hold_) cv_.wait(lk); slot_ = std::move(data); hold_ = true; cv_.notify_one(); } T get() { Lock lk(mtx_); while (!hold_) cv_.wait(lk); cv_.notify_one(); hold_ = false; return std::move(slot_); } };
mt_slot
クラスは、生産者−消費者問題(Producer-Consumer problem)の同期機構として利用できる。この設計パターンでは、生産者スレッドでデータのput
を順次行い、消費者スレッドはデータをget
し続けることになる。
問題:
- 1生産者スレッド−1消費者スレッドのとき、
mt_slot
クラス内でデッドロックを引き起こす可能性はあるか? - 2生産者スレッド−2消費者スレッドではどうか?デッドロックの可能性があるならば、どのような実行が行われた時か?
実行可能コード:https://gist.github.com/yohhoy/191757eaa0fe8dfa39e8 (C++11版, Pthreads版)
解答編 → id:yohhoy:20140930