【发布时间】:2017-06-19 05:06:25
【问题描述】:
我的问题如下图所示。 std::condition_variable 上的通知可能会被线程 II 错过;线程 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;
}
有什么办法可以解决这个问题吗?
(应用程序)。考虑类似带有“wait(state)”、“start”和“cancel”方法的“alarm”类。它有关联的线程,即“服务员”线程。所有方法都可以在单个对象上调用。虽然取消和启动可以与额外的互斥锁同步,但由于明显的原因不能等待。它可以通过在每次等待之前简单地存储一些 ulong 计数器的状态然后比较存储的和当前的状态来解决 - 如果它们不同(通过启动或取消递增),然后状态被切换,通知发生。
【问题讨论】:
-
第二个
condition_variable?尽管您的绘图很有帮助,但您可能需要考虑 editing 您的问题以包含 minimal reproducible example -
我觉得如果线程 3 必须等待线程 1 和线程 2,那么线程 1 应该通知线程 2,线程 2 应该通知线程 3。你所拥有的是试图保护太多太少了。
-
从我可以看到你的线程
#3改变了 state 而不管任何其他线程可能在做什么。我能看到让线程#3与其他线程合作的唯一方法是像处理其他线程一样放入等待和状态测试代码。
标签: c++ multithreading synchronization