作为it turns out,condition_variable::wait_for
应该真正被称为condition_variable::wait_for_or_possibly_indefinitely_longer_than
,因为它需要在真正超时并返回之前重新获取锁。
请参阅this program进行演示。
有没有办法表达,“看,我真的只有两个秒。如果myPredicate()
当时仍然是假的和/或锁仍然锁定,我不会不管怎样,只要随便继续,并给我一个检测它的方法。“
类似的东西:
bool myPredicate();
auto sec = std::chrono::seconds(1);
bool pred;
std::condition_variable::cv_status timedOut;
std::tie( pred, timedOut ) =
cv.really_wait_for_no_longer_than( lck, 2*sec, myPredicate );
if( lck.owns_lock() ) {
// Can use mutexed resource.
// ...
lck.unlock();
} else {
// Cannot use mutexed resource. Deal with it.
};
答案 0 :(得分:7)
我认为您滥用了condition_variable
的锁定。它仅用于保护条件,而不是用于保护耗时的工作。
您的示例可以通过将mutex
拆分为两个来轻松修复 - 一个用于关键部分,另一个用于保护ready
条件的修改。这是修改后的片段:
typedef std::unique_lock<std::mutex> lock_type;
auto sec = std::chrono::seconds(1);
std::mutex mtx_work;
std::mutex mtx_ready;
std::condition_variable cv;
bool ready = false;
void task1() {
log("Starting task 1. Waiting on cv for 2 secs.");
lock_type lck(mtx_ready);
bool done = cv.wait_for(lck, 2*sec, []{log("Checking condition..."); return ready;});
std::stringstream ss;
ss << "Task 1 finished, done==" << (done?"true":"false") << ", " << (lck.owns_lock()?"lock owned":"lock not owned");
log(ss.str());
}
void task2() {
// Allow task1 to go first
std::this_thread::sleep_for(1*sec);
log("Starting task 2. Locking and sleeping 2 secs.");
lock_type lck1(mtx_work);
std::this_thread::sleep_for(2*sec);
lock_type lck2(mtx_ready);
ready = true; // This happens around 3s into the program
log("OK, task 2 unlocking...");
lck2.unlock();
cv.notify_one();
}
它的输出:
@2 ms: Starting task 1. Waiting on cv for 2 secs.
@2 ms: Checking condition...
@1002 ms: Starting task 2. Locking and sleeping 2 secs.
@2002 ms: Checking condition...
@2002 ms: Task 1 finished, done==false, lock owned
@3002 ms: OK, task 2 unlocking...
答案 1 :(得分:0)
有没有办法表达,&#34;看,我真的只有两秒钟。如果 myPredicate()在那时仍然是假的和/或锁定仍然是 锁定,我不在乎,只要坚持下去......&#34;
是的,有办法,但遗憾的是wait_for
必须是手动的。由于Spurious Wakeup,wait_for
无限期等待。想象你的循环:
while(!myPredicate())
cv.wait_for(lock, std::chrono::duration::seconds(2);
虚假唤醒可以在任意平台上随时发生。想象一下,在你的情况下它发生在200毫秒内。因此,在没有任何外部通知的情况下wait_for()
将在循环条件中唤醒并检查myPredicate()
。
正如预期的那样,条件将为假,因此循环将为真,并且将再次执行cv.wait_for(..)
,新的2秒。这就是无限运行的方式。
您可以自己控制更新持续时间,也可以使用最终在wait_until()
中调用的wait_for()
。
答案 2 :(得分:0)
实际上,condition_variable::wait_for
完全符合您的要求。您的示例的问题在于您锁定了2秒的睡眠以及ready = true
赋值,使得条件变量甚至无法在达到时间限制之前评估谓词。
将std::this_thread::sleep_for(2*sec);
行放在锁外,亲眼看看。