We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
wait_loop
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
原文:
等待条件变量满足条件——带超时功能 using namespace std::chrono_literals; std::condition_variable cv; bool done{}; std::mutex m; bool wait_loop(){ const auto timeout = std::chrono::steady_clock::now() + 500ms; std::unique_lock<std::mutex> lk{ m }; while(!done){ if(cv.wait_until(lk,timeout) == std::cv_status::timeout){ std::cout << "超时 500ms\n"; break; } } return done; } 运行测试。
等待条件变量满足条件——带超时功能
using namespace std::chrono_literals; std::condition_variable cv; bool done{}; std::mutex m; bool wait_loop(){ const auto timeout = std::chrono::steady_clock::now() + 500ms; std::unique_lock<std::mutex> lk{ m }; while(!done){ if(cv.wait_until(lk,timeout) == std::cv_status::timeout){ std::cout << "超时 500ms\n"; break; } } return done; }
运行测试。
这段代码意图表达使用条件变量的超时功能,即使用 wait_until 函数,并提供了 godbolt 的完整运行示例。此时看不出什么问题,完整代码如下所示:
wait_until
#include <iostream> #include <condition_variable> #include <mutex> #include <chrono> #include <thread> #include <future> using namespace std::chrono_literals; std::condition_variable cv; bool done{}; std::mutex m; bool wait_loop(){ const auto timeout = std::chrono::steady_clock::now() + 500ms; std::unique_lock<std::mutex> lk{ m }; while(!done){ if(cv.wait_until(lk,timeout) == std::cv_status::timeout){ std::cout << "超时 500ms\n"; break; } } return done; } void trigger(){ { std::lock_guard<std::mutex> lk{ m }; done = true; } cv.notify_one(); } int main() { auto future = std::async(std::launch::async, wait_loop); std::thread t{ trigger }; t.join(); if(future.get()){ std::cout << "没有超时\n"; }else{ std::cout << "超时\n"; } }
运行结果:
没有超时
然而大多数读者会尝试修改此代码,希望直接在 trigger 函数添加 sleep 延时,超过 500ms 就会打印输出:
trigger
超时 500ms 超时
想法很美好,如果延时是添加在 lock_guard 之前,即互斥量上锁(lock)之前,那么没有问题,可以得到我们预期的结果
void trigger() { { std::this_thread::sleep_for(1s); std::lock_guard<std::mutex> lk{ m }; done = true; } cv.notify_one(); }
但是,如果这个延时,是在 lock_guard 之后,即上锁(lock)之后,那么就会出现问题。
void trigger() { { std::lock_guard<std::mutex> lk{ m }; std::this_thread::sleep_for(1s); done = true; } cv.notify_one(); }
超时 500ms 没有超时
是不是感到无法理解?前后矛盾?那么产生这个问题的原因是什么呢?
我们为代码添加一些打印日志,完整如下:
#include <iostream> #include <condition_variable> #include <mutex> #include <chrono> #include <thread> #include <future> using namespace std::chrono_literals; std::condition_variable cv; bool done{}; std::mutex m; bool wait_loop() { const auto timeout = std::chrono::steady_clock::now() + 500ms; std::unique_lock<std::mutex> lk{ m }; std::cout << "wait_loop\n"; while (!done) { if (cv.wait_until(lk, timeout) == std::cv_status::timeout) { std::cout << "超时 500ms" << '\n'; break; } } return done; } void trigger() { { std::lock_guard<std::mutex> lk{ m }; std::this_thread::sleep_for(std::chrono::seconds(2)); done = true; std::cout << "trigger 延时结束" << '\n'; } cv.notify_one(); } int main() { auto future = std::async(std::launch::async, wait_loop); std::thread t{ trigger }; t.join(); if (future.get()) { std::cout << "没有超时\n"; } else { std::cout << "超时\n"; } }
wait_loop trigger 延时结束 超时 500ms 没有超时
我们来研究一下
cv.wait_until(lk, timeout)
lock.lock()
break
return done
done
true
future.get()
我没有提 cv.notify_one();,因为不重要,它会因为超时而解除阻塞,而不是等到最后调用函数唤醒。
cv.notify_one();
我们解释了这个问题,修改方式非常简单,别返回 done,直接 return true、return false。
return true
return false
bool wait_loop() { const auto timeout = std::chrono::steady_clock::now() + 500ms; std::unique_lock<std::mutex> lk{ m }; while (!done) { if (cv.wait_until(lk, timeout) == std::cv_status::timeout) { std::cout << "超时 500ms\n"; return false; } } return true; }
也就不存在上面的问题了。
The text was updated successfully, but these errors were encountered:
1. 修改第四章时间点的例子 .count() 以兼容早期标准
.count()
00b226d
2. 修改展示条件变量超时功能的示例 #15 3. C++20 信号量(完成本节部分内容)#12
既然这个 issue 已经被 resolved 了,为何不 close 它?
Sorry, something went wrong.
No branches or pull requests
说明问题
原文:
这段代码意图表达使用条件变量的超时功能,即使用
wait_until
函数,并提供了 godbolt 的完整运行示例。此时看不出什么问题,完整代码如下所示:运行结果:
然而大多数读者会尝试修改此代码,希望直接在
trigger
函数添加 sleep 延时,超过 500ms 就会打印输出:想法很美好,如果延时是添加在 lock_guard 之前,即互斥量上锁(lock)之前,那么没有问题,可以得到我们预期的结果
但是,如果这个延时,是在 lock_guard 之后,即上锁(lock)之后,那么就会出现问题。
运行结果:
是不是感到无法理解?前后矛盾?那么产生这个问题的原因是什么呢?
解释原因
我们为代码添加一些打印日志,完整如下:
运行结果:
我们来研究一下
cv.wait_until(lk, timeout)
;也就是解锁互斥量,直到“虚假唤醒”、其它线程调用唤醒函数、超时,才会唤醒。wait_until
调用超时,解除阻塞,但是需要:在解除阻塞时调用lock.lock()
,然而根本无法成功调用,会一直阻塞,因为目前锁被trigger
线程持有,还未释放(unlock)。break
。return done
。然而此时done
已经被设置为true
。future.get()
返回true
,打印:“没有超时”。我没有提
cv.notify_one();
,因为不重要,它会因为超时而解除阻塞,而不是等到最后调用函数唤醒。我们解释了这个问题,修改方式非常简单,别返回 done,直接
return true
、return false
。也就不存在上面的问题了。
运行测试。
The text was updated successfully, but these errors were encountered: