スレッドプールのコードの中でわからなかったcondition_variableについて調べた。
条件変数と訳される。wait()で待機状態にしたスレッドに対して、別のスレッドからnotify_all()で通知を送ると待機していたスレッドが動き出す。
#pragma warning(disable:4996) #include <iostream> #include <functional> #include <thread> #include <mutex> #include <condition_variable> std::mutex mtx; std::condition_variable cv;
void func1() { for (size_t i = 0; i < 10;i++) { _sleep(10); printf("func1 # %d\n", i); if (i == 5) { printf("*** func1 から通知を送る *** \n"); cv.notify_all(); } } }
void func2() { printf("待機開始\n"); std::unique_lock<std::mutex> ul(mtx); cv.wait(ul); printf("通知が来たので func2 スレッド再開\n"); for (size_t i = 0; i < 10; i++) { _sleep(10); printf("func2 : %d\n", i); } }
int main() { std::thread th1(func1); std::thread th2(func2); th1.join(); th2.join(); std::cout << "Hello World!\n"; }
condition_variableは、.wait()の場所で、notify_all()などで通知が来るまで待機するのだが、「たまに、なぜか知らないが、どういうわけか通知が来ていないのに待機が解除されてしまいスレッドが走り出す」という現象が起こるらしい。これをspurious wakeupといい、condition_variableを使う場合、この現象への対応をしておかなければならないという。
ステート変数notifyを追加し、この変数がtrueの時だけwaitを解除する。
#pragma warning(disable:4996) #include <iostream> #include <functional> #include <thread> #include <mutex> #include <condition_variable> bool notify = false; // Spurious Wakeup考慮 ステート変数 std::mutex mtx; std::condition_variable cv; void func1() { for (size_t i = 0; i < 10;i++) { _sleep(10); printf("func1 # %d\n", i); if (i == 5) { printf("*** func1 から通知を送る *** \n"); notify = true;// notify_allするときにしかnotifyがtrueになることはない cv.notify_all(); } } } void func2() { printf("待機開始\n"); std::unique_lock<std::mutex> ul(mtx); cv.wait(ul, [&]{return notify; });// notifyがtrueの時だけ待機解除 printf("通知が来たので func2 スレッド再開\n"); for (size_t i = 0; i < 10; i++) { _sleep(10); printf("func2 : %d\n", i); } } int main() { std::thread th1(func1); std::thread th2(func2); th1.join(); th2.join(); std::cout << "Hello World!\n"; }