简体   繁体   English

如果存在条件/谓词,通知条件变量是否保证唤醒具有成功条件/谓词的线程?

[英]Does notifying a condition variable guarantee the wake-up of a thread with a successful condition/predicate if one exists?

The information I've found on cppreference is vague in this regard, so I'm asking here.我在cppreference上找到的信息在这方面含糊不清,所以我在这里问。 Say I have two threads waiting on a condition with different one having a true predicate, and the other one a false one (eg condition.wait(lock, [=]{ return some_condition; } ). The main thread decides to randomly notify one of them with cond.notify_one() .假设我有两个线程在等待一个条件,其中一个具有真谓词,另一个是假的(例如condition.wait(lock, [=]{ return some_condition; } )。主线程决定随机通知一个其中有cond.notify_one()

Assume that the waiting thread selected is the one where the predicate is false.假设选择的等待线程是谓词为假的线程。 Is the thread going to implicitly notify the next one (if there are any left), or will it be doomed to wait until spurious wakeup?线程是否会隐式通知下一个线程(如果还有剩余),还是注定要等到虚假唤醒?

In case only a single thread is woken up no matter whether its condition succeeds or fails, what would a good way for the first thread to try waking the next one up for a guaranteed successful notify?如果只有一个线程被唤醒,无论其条件是成功还是失败,第一个线程尝试唤醒下一个线程以保证成功通知的好方法是什么? A naive fix:一个天真的修复:

condition.wait(lock, [=] {
    if (!some_condition) condition.notify_one();
    return some_condition;
});

Other than pessimization, the "notify wave" may notify the same threads repeatedly which is ineffective + never halt in case no threads have successful predicates.除了悲观之外,“通知波”可能会重复通知相同的线程,这是无效的+永远不会停止,以防没有线程有成功的谓词。 A notify_all() won't work, because we may accidentally end waking up multiple threads that satisfy the condition, meanwhile we only want a single one to go through at most.一个notify_all()是行不通的,因为我们可能会不小心结束唤醒多个满足条件的线程,同时我们最多只需要一个到 go 的线程。

A notify_all() won't work, because we may accidentally end waking up multiple threads that satisfy the condition, meanwhile we only want a single one to go through at most.一个 notify_all() 是行不通的,因为我们可能会不小心结束唤醒多个满足条件的线程,同时我们最多只需要一个到 go 的线程。

That is not entirely accurate.这并不完全准确。 Only one thread can lock a given mutex at a time, no matter what.无论如何,一次只有一个线程可以锁定给定的互斥锁。 If all execution threads who are waiting on the condition variable locked the same mutex (as they should) before they started to wait on the condition variable, then only one of those execution threads will successfully re-lock the mutex and "wake up", and return from wait() .如果所有等待条件变量的执行线程在开始等待条件变量之前锁定了同一个互斥锁(应该如此),那么只有一个执行线程将成功重新锁定互斥锁并“唤醒”,并从wait()返回。 When it unlocks the mutex the next scheduled execution thread will be able to re-lock it and return from its wait() .当它解锁互斥锁时,下一个计划执行线程将能够重新锁定它并从它的wait()中返回。 And so on.等等。 notify_all() does not result in all execution threads galloping forward, full speed ahead. notify_all()不会导致所有执行线程向前疾驰,全速向前。 Effectively only one thread gets woken up, at a time, because they all must re-lock the same mutex.实际上,一次只有一个线程被唤醒,因为它们都必须重新锁定同一个互斥体。 This single-threads them.这对它们进行单线程处理。

All execution threads get scheduled to be woken up by notify_all , and they will all get woken up.所有执行线程都被安排notify_all唤醒,它们都会被唤醒。 However, effectively, only one execution thread will end up woken first, and lock the mutex.然而,实际上,只有一个执行线程会首先被唤醒,并锁定互斥体。 When it unlocks the mutex the next execution thread, that got scheduled to be woken up by notify_all() , will be able to re-lock it, and so on.当它解锁互斥锁时,下一个执行线程(计划由notify_all()唤醒)将能够重新锁定它,依此类推。

Next, let's look at what wait() with a predicate is logically equivalent to :接下来,让我们看看带有谓词的wait()逻辑上等价于

while (!stop_waiting()) {
    wait(lock);
}

Note that the predicate, here named stop_waiting is checked while the mutex is locked , and it is checked only after the "real" wait() , the one that doesn't check the predicate condition, returns.请注意,谓词(此处名为stop_waiting在互斥锁处于锁定状态时进行检查,并且仅在不检查谓词条件的“真正” wait()返回后才检查。

Therefore, the solution to your problem is simpler than you think:因此,您的问题的解决方案比您想象的要简单:

  1. Use notify_all() .使用notify_all()

  2. Whichever thread succeeds in returning from wait() simply needs to do whatever is needed so that the predicate condition is no longer satisfied.无论哪个线程成功地从wait()中返回,只需要做任何需要的事情,以便不再满足谓词条件。 The exact manner of doing so depends on the predicate.这样做的确切方式取决于谓词。

So, in the end, one of the execution threads will get woken up, and it will "turn off" the predicate condition.因此,最后,其中一个执行线程将被唤醒,它将“关闭”谓词条件。 After this execution thread unlocks the mutex, all the other ones will wake up, but the predicate condition is no longer met.此执行线程解锁互斥锁后,其他所有的都会唤醒,但不再满足谓词条件。 The End.结束。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 std::condition_variable::notify_one: 如果有些线程有错误的谓词,它会唤醒多个线程吗? - std::condition_variable::notify_one: does it wake multiple threads if some have false predicate? 为什么 boost::condition_variable 可以使用 pthread_cond_signal 只唤醒一个线程 - Why boost::condition_variable can use pthread_cond_signal to wake up only one thread 在不使用条件变量的情况下唤醒线程的最快方法 - fastest way to wake up a thread without using condition variable 线程何时从condition.wait()中唤醒 - when does a thread wake up from condition.wait() 为什么只有一个锁和一个原子计数器会错误地唤醒条件变量? - Why does the condition variable wake up erroneously with only one lock and an atomic counter? 即使有谓词,condition_variable 也不会被通知唤醒 - condition_variable doesn't get notified to wake up even with a predicate 如果没有线程需要唤醒,是否需要获取锁并通知condition_variable? - Is it necessary to acquire the lock and notify condition_variable if no thread needs to wake up? 如何使用条件变量唤醒多个线程 - How to wake up multiple threads using condition variable Spurios唤醒和条件变量 - Spurios wake up and condition variables 条件变量的谓词 - predicate for condition variable
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM