我的问题如下图所示。线程II可以错过std::condition_variable
的通知;线程III可以在它之前获得锁定并改变条件。
/*
Thread I Thread II Thread III
_____________________________________________________________
| lock M | wait for notify | wait for M | |
| cond = stateA | | | |
| notify | unblock | | |
| unlock M | wait for M | lock M | |
| | | cond = stateB | |
| | lock M | unblock M | |
| | check if cond == stateA | | |
| | ... | | \ / t
*
*/
#include <iostream>
#include <condition_variable>
#include <chrono>
#include <thread>
#include <limits>
#include <mutex>
int main()
{
using namespace std::chrono ;
std::mutex mtx ;
std::condition_variable cv ;
enum EState
{
A , B
} state = B ; // mtx
// possible workaround
using count_t = unsigned long long ;
count_t set_A_state_count = 0 ; // mtx
// 18,446,744,073,709,551,615 - number, that may cause missing ;
// ( if Thread III function would get executed exactly this number of times
// before Thread II acquire the mutex )
// believe it is not relevant for present days.
auto ThreadI = [ &set_A_state_count , &cv ,
&mtx , &state ] ()
{
std::lock_guard< std::mutex > lock { mtx } ;
state = A ;
++ set_A_state_count ;
cv.notify_one() ;
} ;
auto ThreadIII = [ &cv , &mtx , &state ] ()
{
std::lock_guard< std::mutex > lock { mtx } ;
state = B ;
} ;
std::unique_lock< std::mutex > lock { mtx } ;
std::thread thI ( ThreadI ) , thIII ( ThreadIII ) ;
const auto saved_count = set_A_state_count ;
if ( state != A ) {
while( saved_count == set_A_state_count ) { // pred ()
// releasing and waiting
cv.wait( lock ) ;
// acquiring - place where ThreadIII can outrun main thread ( ThreadII on the inlustration )
}
}
count_t times = ( saved_count < set_A_state_count ) ?
set_A_state_count - saved_count
: std::numeric_limits< count_t >::max() -
set_A_state_count + saved_count ;
std::cout << "state was changed to A " << times << " times." << std::flush ;
thI.join() ;
thIII.join() ;
return 0;
}
有没有办法解决这个问题。?
(应用程序)。考虑像“闹钟”这样的事情。等待(状态)&#39;,&#39;开始&#39;和&#39;取消&#39;方法。它有关联的线程,即服务员&#34;线。可以在单个对象上调用所有方法。虽然取消和启动可以与其他互斥锁同步,但是等待显而易见的原因无法完成。它可以通过简单地在每次等待之前存储一些ulong计数器的状态然后比较存储和当前 - 如果它们不同(通过开始或取消递增),然后状态被切换,通知发生来进行操作。
答案 0 :(得分:1)
线程II可能会错过
std::condition_variable
上的通知;
如果在发出通知时没有线程等待它,则可能会错过条件变量通知。代码必须等待状态的改变。条件变量通知提示状态可能已更改,必须重新评估。
您有2个主题赛车相应地将state
更改为A
和B
。它们之间没有排序约束,因此state
可以是A
或B
。在后一种情况下,等待state == A
的线程永远阻塞。