condition_variable: スレッド間の通知
ビジーウェイトを避け、効率的にスレッドを待機。
condition_variable
スレッド間の待機・通知。
wait
条件が満たされるまでブロック。
notify
待機中のスレッドを起こす。
条件変数
条件変数は `std::unique_lock` と組み合わせて使います。「待機(wait)」はロックを一時的に解放してスリープし、通知が来ると再びロックを取得して起き上がります。これにより、リソースを消費せずにイベントを待つことができます。
#include <condition_variable>#include <mutex>#include <queue>
std::queue<int> queue;std::mutex mtx;std::condition_variable cv;
// プロデューサーvoid producer() { std::lock_guard<std::mutex> lock(mtx); queue.push(42); cv.notify_one(); // 待機中のスレッドを起こす}
// コンシューマーvoid consumer() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return !queue.empty(); }); // 条件を待つ int val = queue.front(); queue.pop();}実行結果
producer: queue.push(42)\nconsumer: cv.wait() → 通知で起動\nval = 42
Bad
// ❌ Bad: ビジーウェイトwhile (queue.empty()) { std::this_thread::sleep_for(10ms); // CPU浪費}Good
// ✅ Good: condition_variablecv.wait(lock, []{ return !queue.empty(); });パターン
// タイムアウト付き waitif (cv.wait_for(lock, std::chrono::seconds(1), []{ return !queue.empty(); })) { // データ到着} else { // タイムアウト}
// 全スレッドを起こすcv.notify_all();
// 典型的なパターン: Producer-Consumerclass BlockingQueue { std::queue<int> q; std::mutex m; std::condition_variable cv;public: void push(int val) { { std::lock_guard lock(m); q.push(val); } cv.notify_one(); } int pop() { std::unique_lock lock(m); cv.wait(lock, [this]{ return !q.empty(); }); int val = q.front(); q.pop(); return val; }}; Tip: wait には必ず条件述語を渡す(スプリアスウェイクアップ対策)。
合格ライン
wait/notify を使える
Producer-Consumer を実装できる
参考リンク
演習課題
課題1: Producer-Consumer
condition_variable を使って Producer-Consumer パターンを実装してください。
課題2: notify_all
複数の待機スレッドを notify_all で一斉に起こしてください。