std::condition_variable::notify_one
void notify_one() noexcept; |
(C++11以上) | |
*this で待機しているスレッドがあれば、 notify_one の呼び出しは待機中のスレッドのひとつのブロックを解除します。
引数
(なし)
戻り値
(なし)
ノート
notify_one()/notify_all() および wait()/wait_for()/wait_until() の3つのアトミック部分 (unlock+wait、wakeup、lock) 各々の効果は、アトミック変数の変更順序として考えることができる単一の全順序で行われます。 この順序は個々の条件変数に固有です。 これにより、例えば notify_one() が遅延され、 notify_one() の呼び出しの後に待機を開始したスレッドをブロック解除することは、ありえなくなります。
通知スレッドは、待機中のスレッドが保持しているものと同じミューテックスのロックを保持している必要はありません。 実際、それは効率の悪いことです。 通知されたスレッドは、通知スレッドがロックを解放するのを待って、すぐに再びブロックされます。 しかし、実装によっては (特に pthreads 実装の多くでは) この状況を認識し、 notify の呼び出しで、待機中のスレッドを、起床させずに条件変数のキューからミューテックスのキューに直接転送し、この「起きてすぐ待つ」シナリオを回避します。
とはいえ、イベントの正確なスケジューリングが要求されるときは、ロック下で通知することが必要になる場合があります。 例えば、待機中のスレッドが、条件が満たされた場合にプログラムを終了させる場合、通知スレッドの条件変数の破棄が発生します。 ミューテックスのロックを解除した後、しかし通知をする前に spurious wakeup が発生すると、破棄済みのオブジェクトに対して notify を呼ぶ結果となります。
例
#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>
std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cout << "Waiting... \n";
cv.wait(lk, []{return i == 1;});
std::cout << "...finished waiting. i == 1\n";
done = true;
}
void signals()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Notifying falsely...\n";
cv.notify_one(); // waiting thread is notified with i == 0.
// cv.wait wakes up, checks i, and goes back to waiting
std::unique_lock<std::mutex> lk(cv_m);
i = 1;
while (!done)
{
std::cout << "Notifying true change...\n";
lk.unlock();
cv.notify_one(); // waiting thread is notified with i == 1, cv.wait returns
std::this_thread::sleep_for(std::chrono::seconds(1));
lk.lock();
}
}
int main()
{
std::thread t1(waits), t2(signals);
t1.join();
t2.join();
}
出力例:
Waiting...
Notifying falsely...
Notifying true change...
...finished waiting. i == 1
関連項目
| 待機中のスレッドすべてに通知します (パブリックメンバ関数) | |
cnd_signal の C言語リファレンス
|