C++標準ライブラリの future/promise を利用してone-shotイベントを実現する。
本記事での “one-shotイベント” は、1度しか使えないスレッド間イベント待機/通知機構を指している。環境依存の実装であれば、WaitForSingleObject
/SetEvent
(Windows API)やsem_wait
/sem_post
(POSIX)の組で実現可能*1。
std::promise<void>
(イベント通知側)とstd::shared_future<void>
(複数のイベント待機側)を利用したone-shotイベントの実装コード。
#include <thread> #include <future> void func(std::shared_future<void> ftr) { //... ftr.wait(); // イベント待機 //... } int main() { std::promise<void> prm; auto ftr = prm.get_future().share(); std::thread t1(func, ftr), t2(func, ftr); //... prm.set_value(); // イベント通知 //... t1.join(); t2.join() }
shared_future::wait
でイベント待機中の2つのスレッドt1
, t2
に対し、mainスレッドからpromise::set_value
でイベントシグナル通知を行っている。また、イベント待機をshared_future::get
で行い、通知側はpromise::set_value
(正常時)とset_exception
(異常時)で使い分ければ待機側スレッドへの例外通知を実現できる。
おまけ:mutex+condition_variable版
mutex
とcondition_variable
を利用したイベントオブジェクトの単純な実装コード。こちらはイベントリセット(reset
メンバ関数)を提供するため、イベントオブジェクトの使い回しが可能となる。
#include <mutex> #include <condition_variable> class event { private: std::mutex m_; std::condition_variable cv_; bool flag_; public: explicit event(bool init_flag = false) : flag_(init_flag) {} event(const event&) = delete; event& operator=(const event&) = delete; void wait() { std::unique_lock<std::mutex> lk(m_); cv_.wait(lk, [&]{ return flag_; }); } void set() { std::lock_guard<std::mutex> lk(m_); flag_ = true; cv_.notify_all(); } void reset() { std::lock_guard<std::mutex> lk(m_); flag_ = false; } };