【C++】std::condition_variableで簡単にスレッド同期【標準ライブラリ】
std::condition_variableとは
std::condition_variable
は、C++の標準ライブラリで提供されるスレッド同期のための仕組みです。
主に std::mutex
と std::unique_lock
を組み合わせて使われ、特定の条件が満たされるまでスレッドを待機させたり、条件が変わったことを通知するために使用されます。
基本的な使い方
std::condition_variable
は、notify_one()
や notify_all()
を用いて待機中のスレッドに通知を送ることができます。
以下は基本的な使用例です:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; });
std::cout << "Worker thread is running!\n";
}
int main() {
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one();
t.join();
return 0;
}
上記のコードでは、cv.wait()
が ready
変数が true
になるのを待ち、notify_one()
で通知を送ることでスレッドが実行を再開します。
複数スレッドでの使用例
notify_all()
を使うと、すべての待機スレッドに通知を送ることができます。
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker(int id) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; });
std::cout << "Thread " << id << " is running!\n";
}
int main() {
std::vector<std::thread> workers;
for (int i = 0; i < 5; ++i) {
workers.emplace_back(worker, i);
}
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_all();
for (auto &t : workers) {
t.join();
}
return 0;
}
スプリアスウェイクアップへの対策
スプリアスウェイクアップ(意図しない通知なしの起床)を防ぐために、cv.wait()
にはラムダ関数を使うのが一般的です。
タイムアウト付きの待機
cv.wait_for()
や cv.wait_until()
を使用すると、一定時間待機した後に処理を進めることができます。
Producer-Consumerパターンの実装
std::condition_variable
は、Producer-Consumerパターンの実装によく使われます。
デッドロックを防ぐための注意点
デッドロックを防ぐためには、ロックの取得順序を固定したり、ロックの持ち時間を最小限にすることが重要です。
まとめ
std::condition_variable
は、マルチスレッド環境におけるスレッド間の同期に役立ちます。
正しく使用することで、効率的なスレッド管理を実現できます。