"数据竞赛"通知条件变量并解锁相关的互斥锁

时间:2017-06-19 05:06:25

标签: c++ multithreading synchronization

我的问题如下图所示。线程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计数器的状态然后比较存储和当前 - 如果它们不同(通过开始或取消递增),然后状态被切换,通知发生来进行操作。

1 个答案:

答案 0 :(得分:1)

  

线程II可能会错过std::condition_variable上的通知;

如果在发出通知时没有线程等待它,则可能会错过条件变量通知。代码必须等待状态的改变。条件变量通知提示状态可能已更改,必须重新评估。

您有2个主题赛车相应地将state更改为AB。它们之间没有排序约束,因此state可以是AB。在后一种情况下,等待state == A的线程永远阻塞。