在等待之前必须检查 std::condition_variable 谓词吗?
Must the std::condition_variable predicate be checked before waiting?
我不清楚文档语言是否必须在等待之前检查 std::condition_variable 的谓词。
在 cppreference 上,有声明:
Any thread that intends to wait on std::condition_variable has to
1. ...
2. check the condition, in case it was already updated and notified
实际上,好像不需要查一个。如果没有,我只是担心未定义的行为。
我比较关心的情况是consumer在producer之后上线(即condition variable在另一个线程开始等待之前已经被一个线程通知):
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
int main() {
std::condition_variable condition_var;
std::mutex mutex;
std::vector<std::thread> threads;
bool flag = false;
// Producer
threads.emplace_back([&]() {
{
std::lock_guard<std::mutex> lock(mutex);
flag = true;
printf("%s\n", "flag = true");
}
condition_var.notify_all();
});
// Consumer
threads.emplace_back([&]() {
std::this_thread::sleep_for(std::chrono::seconds(3));
{
std::unique_lock<std::mutex> lock(mutex);
condition_var.wait(lock, [&]() { return flag; });
printf("%s\n", "Consumer finished");
}
});
for (auto& thread : threads) {
if (thread.joinable()) {
thread.join();
}
}
return 0;
}
在上面的示例中,生产者启动并通知条件变量。消费者在那之后启动,并在检查条件变量之前进入睡眠状态几秒钟。这实际上确保了消费者在生产者通知条件变量后开始等待。
尽管如此,代码在我的计算机上完成并且不会无限期地挂起。事实上,由于它完成的速度如此之快,我认为这不是虚假唤醒造成的,但我不确定如何检查。
没有
如果您为 wait
提供谓词,则在调用该函数之前无需自行检查。
The cited cppreference.com article is arguably misleading (and/or wrong) in this regard, though the article for wait
is on the money in its code-based example, which is identical to the definition given in the standard:
while (!pred())
wait(lock);
该页面上的第二组要点似乎是从更高层次的角度来解决问题的,没有考虑 wait()
调用本身确实执行检查 pred()
给你,如果你提供一个。
这可能是因为 wait()
的重载 不会 接受 pred
,并且通常 不要求条件变量知道您正在测试的条件:很有可能用它来检查某些 "external" 条件。但是,如今,我们通常只是将 lambda 推入 pred
并完成它,所以......
几周前我遇到了这种不一致(之前的讨论 here),但还没有为这篇文章想出更好的措辞。
我不清楚文档语言是否必须在等待之前检查 std::condition_variable 的谓词。
在 cppreference 上,有声明:
Any thread that intends to wait on std::condition_variable has to
1. ...
2. check the condition, in case it was already updated and notified
实际上,好像不需要查一个。如果没有,我只是担心未定义的行为。
我比较关心的情况是consumer在producer之后上线(即condition variable在另一个线程开始等待之前已经被一个线程通知):
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
int main() {
std::condition_variable condition_var;
std::mutex mutex;
std::vector<std::thread> threads;
bool flag = false;
// Producer
threads.emplace_back([&]() {
{
std::lock_guard<std::mutex> lock(mutex);
flag = true;
printf("%s\n", "flag = true");
}
condition_var.notify_all();
});
// Consumer
threads.emplace_back([&]() {
std::this_thread::sleep_for(std::chrono::seconds(3));
{
std::unique_lock<std::mutex> lock(mutex);
condition_var.wait(lock, [&]() { return flag; });
printf("%s\n", "Consumer finished");
}
});
for (auto& thread : threads) {
if (thread.joinable()) {
thread.join();
}
}
return 0;
}
在上面的示例中,生产者启动并通知条件变量。消费者在那之后启动,并在检查条件变量之前进入睡眠状态几秒钟。这实际上确保了消费者在生产者通知条件变量后开始等待。
尽管如此,代码在我的计算机上完成并且不会无限期地挂起。事实上,由于它完成的速度如此之快,我认为这不是虚假唤醒造成的,但我不确定如何检查。
没有
如果您为 wait
提供谓词,则在调用该函数之前无需自行检查。
The cited cppreference.com article is arguably misleading (and/or wrong) in this regard, though the article for wait
is on the money in its code-based example, which is identical to the definition given in the standard:
while (!pred())
wait(lock);
该页面上的第二组要点似乎是从更高层次的角度来解决问题的,没有考虑 wait()
调用本身确实执行检查 pred()
给你,如果你提供一个。
这可能是因为 wait()
的重载 不会 接受 pred
,并且通常 不要求条件变量知道您正在测试的条件:很有可能用它来检查某些 "external" 条件。但是,如今,我们通常只是将 lambda 推入 pred
并完成它,所以......
几周前我遇到了这种不一致(之前的讨论 here),但还没有为这篇文章想出更好的措辞。