我想使用std :: condition_variable作为线程调用的方法的退出条件。我设想它会像这样使用:
std::mutex m;
std::condition_variable exit_condition;
void func() {
std::unique_lock<std::mutex> lk(m);
while (exit_condition.wait_for(lk, std::chrono::milliseconds(0)) == std::cv_status::timeout)
// Do something
}
int main() {
std::thread t(func);
// Do something
exit_condition.notify_one();
t.join();
}
但是,如果零超时,wait_for
的返回值始终为std::cv_status::timeout
。
如果我使用Windows API编写func
,我会这样写:
HANDLE exit_condition;
void func() {
while (WaitForSingleObject(exit_condition, 0) == WAIT_TIMEOUT)
// Do something
}
请注意,我可以使用较小的超时编写func
并退出。
void func() {
std::unique_lock<std::mutex> lk(m);
while (exit_condition.wait_for(lk, std::chrono::milliseconds(10)) == std::cv_status::timeout)
// Do something
}
我有点担心在某些情况下它不会退出。
那么,我可以在某种程度上检查一个没有超时的std :: condition_variable,以保证wait_for
方法的返回值为std::cv_status::no_timeout
吗?
答案 0 :(得分:4)
如果您实际上不需要超时,则可以通过调用wait()
而不是wait_for()
来获得类似的功能。
如果所有这一切的唯一目的是让一个线程告诉另一个线程何时停止运行,那么通常要做的是检查循环顶部的原子bool(while (runnable)
)并切换当你想要循环退出时,它来自另一个线程。
答案 1 :(得分:0)
条件变量不是事件对象。特别是,他们没有记忆。
设置显式退出标志。并且你实际上进行了轮询,因此不需要任何条件变量(除了轮询讨论的优点)。
bool exit_request = false;
std::mutex m;
void func() {
while (true) {
{
std::unique_lock<std::mutex> lk(m);
if (exit_request)
return;
}
do_something();
}
}
int main() {
std::thread t(func);
// Do something
{
std::unique_lock<std::mutex> lk(m);
exit_request = true;
}
t.join();
}
PS。而且,是的,如上所述,在这种情况下会有一个简单的原子旗帜。
答案 2 :(得分:0)
总结答案和各种讨论主题,我想在一个答案中把事情拉到一起。
我原来问题的答案是肯定的,你可以在没有超时的情况下检查std :: condition_variable,但它必须是接受谓词的wait
重载之一。
首先,似乎std:condition_variable
可能不是发出线程退出信号的最佳工具。 std::mutex
和共享bool
或std::atomic<bool>
或std::atomic_flag
效果更好。
如果您计划使用我在问题中提出的std::condition_variable
,请注意虚假唤醒的可能性。根据C ++ 11标准中的3.50.1 [#10],对wait
,wait_for
或wait_until
的调用可能会在不调用notify_one
的情况下返回, notify_all
,或谓词返回true。
这意味着两个指导原则:
wait
返回后的任何代码都必须显式检查谓词的返回值。wait
方法。以下代码在我的回答中完成了原始代码的目标,但安全地完成了。
std::mutex m;
std::condition_variable exit_condition;
bool should_exit;
void func() {
std::unique_lock<std::mutex> lk(m);
while (!exit_condition.wait_for(lk, std::chrono::milliseconds(0), []{return should_exit;})) {
if (should_exit)
break;
// Do something
}
}
int main() {
should_exit = false;
std::thread t(func);
// Do something
should_exit = true;
exit_condition.notify_one();
t.join();
}