Boost.Thread condition_variable便利。
Boost.Threadはよく使うのですが、同期とか排他とか、recursive_mutexだけでゴニョゴニョするだけという
かなりナンセンスな設計しかしていませんでしたが、先日condition_variableが便利だと知りました。
なんせ、よく知らない機能は、ドキュメント読むのも難しいし、逃避しがちなんですよね。
公式ドキュメントから翻訳してみた。
condition_variableクラスとcondition_variable_anyクラスは、
ある(1つの)スレッドに対して、conditionがtrueになった他のスレッドからの通知(notification)を待機するためのメカニズムを提供します。
一般的な用法では、1つのスレッドがmutexをロックしてcondition_variableあるいはcondition_variable_anyのインスタンスのwaitを呼び出します。
スレッドがwaitから起こされたならば、スレッドは適切なconditionが真になっているかどうか、そして処理を継続するかどうかをチェックします。
もし、そのconditionが真でなければ、スレッドは再び待機を続けます。最も単純なケースでは、このconditionとは単なるbooleanの変数です:
boost::condition_variable cond; boost::mutex mut; bool data_ready; void process_data(); void wait_for_data_to_process() { boost::unique_lock<boost::mutex> lock(mut); while(!data_ready) { cond.wait(lock); } process_data(); }
lockがwaitに渡されている所に注目してください。
lockがwaitに渡されると、waitは自動でコンディション変数上の待機スレッドのセット(set of threads waiting on the condition variable)にこのスレッドを追加して、mutexのロックを解除します。
スレッドが起こされたら(When thread is woken)、mutexはwaitの呼び出しがreturnする前に再びロックされます。
これは、共有されるデータを更新したいという要求の元、他のスレッドがmutexを取得することを可能にし、さらにconditionに関連付けられているデータの確実な同期を保証します。その間に、
他のスレッドがconditionをtrueにセットして当該のcondition variableのnotify_oneかnotify_allを呼ぶと、
待機している1つのスレッド、あるいはすべてのスレッドをそれぞれ起こします(wake)。
void retrieve_data(); void prepare_data(); void prepare_data_for_processing() { retrieve_data(); prepare_data(); { boost::lock_guard<boost::mutex> lock(mut); data_ready=true; } cond.notify_one(); }
ちなみに、共有されるデータが更新されるよりも前に同じmutexがロックされていますが、これはnofity_oneの呼び出しを越えてロックされる必要はありません。
この例ではcondition_variable型のオブジェクトを使用しましたが、condition_variable_any型のものでもうまく動作するでしょう。
condition_variable_anyはcondition_variableよりも汎用的で、
condition_variableではwaitに渡すlockがboost::unique_lockでなければならないところを、あらゆる種類のlockやmutexを使って動作するでしょう。
これは幾つかのケースでは、mutex typeの知識に基づいて、最適化のためにcondition_variableを有効にします。condition_variable_anyは大抵condition_variableよりも
複雑な実装を持っていますので。
最後の方に行くにつれて翻訳の精度が悪くなっている気がしますけど、こんな感じですかね。
unique_lockでロックかけてから、conditionが整ってなければwaitにロックを渡す。waitの中でロックは外されて、さらにスレッドは待機状態になる、
(他のスレッドはcondition整えて、通知。)
通知されたらwaitから起き上がって再ロックされる。
再びcondition確認。
これだけでつかえて簡単便利!
timed_waitはLet's Boostのサンプルの中で使われてますね。