提问人:f1msch 提问时间:6/13/2022 最后编辑:Jean-Baptiste Yunèsf1msch 更新时间:6/16/2022 访问量:303
C++11 std::notify_all 和虚假唤醒
c++11 std::notify_all and spurious wakeup
问:
使用 C++11。
由于会导致虚假唤醒,那么为什么会保留但不是一直存在呢?
顺便说一句,可能会导致虚假唤醒吗?std::notify_all
std::notify_all
std::notify_one
std::notify_one
详细阐述我的疑虑:
当我调用 和 时,我的目的通常是实现线程同步。也就是说,更多的线程被阻塞,要等到另一个线程通知其中一个线程才能解除阻塞。std::condition_variable.wait/wait_for/wait_until
std::notify_XXX
那我就打电话去实现这个,但为什么还有另一个,它的目的是什么,或者适合什么情况?
而在我的情况下,当我调用时,它会唤醒所有等待的线程,然后只有一个线程实际上解除了阻塞,其他线程仍然阻塞,这叫虚假唤醒吗?
如果也会调用虚假唤醒?notify_one
notify_all
notify_all
notify_all
notify_one
答:
从 thread.condition/8.3
开始:void std::condition_variable::wait(std::unique_lock<std::mutex>& lock);
当通过调用 或调用 或虚假调用发出信号时,该函数将取消阻止。
notify_one()
notify_all()
所以打电话或不是先决条件。它可以在不调用任何内容的情况下取消阻止。notify_one()
notify_all()
上面的引文来自“C++20 出版后初稿”,但自从它第一次为 C++11 编写以来一直保持不变。
为什么还有另一个,它的目的是什么,或者适合什么情况?
notify_all
notify_all
当您希望所有等待的线程取消阻止时。一个实际情况是什么时候需要关闭。如果你的线程被阻塞了,它们将永远不会完成,并且它们将挂起。wait
join()
带有谓词的示例,表示它应该等到 is 或 is :aborted
true
queue.empty()
false
bool pop_from_queue(T& item) {
std::unique_lock<std::mutex> lock(mtx);
while(queue.empty() && not aborted) cv.wait(lock);
if(aborted) return false; // time to shutdown
// else pick an item from the queue
item = std::move(queue.front());
queue.pop();
return true;
}
当需要关闭时,另一个线程通常会在这里执行以下操作:
aborted = true; // std::atomic<bool>
cv.notify_all();
当我调用nitify_all时,它会唤醒所有等待的线程,然后只有一个线程实际上解封,其他线程仍然阻塞,这叫虚假唤醒吗?
不。虚假唤醒是随时可能发生的唤醒。如果调用 ,等待的线程将全部按顺序唤醒 - 而不是虚假唤醒。notify_all
如果notify_one也会叫虚假唤醒?
它可能会导致虚假唤醒,但这将是一个实现细节。最好的办法是接受线程可能随时唤醒的事实,并在它们唤醒时检查谓词。
我可以精确地控制在等待线程中取消阻止的位置(谁在没有谓词的情况下调用)?
condition_variable.wait
在不检查谓词的情况下,线程唯一确定的是它唤醒了。现在,如果它有正确的理由,它就不会了。
评论
notify_all
wait