互斥和阻止范围

时间:2017-02-26 17:51:20

标签: c++ multithreading mutex

在代码中使用互斥锁:

class Bank{
public:
    Bank():counter(0){};
    void addBankAccount(){
        unique_lock<mutex>  m ( g_Mtx );
        for( int i = 0; i < 1000; i++){
            counter++;
        }
    }

    int getCounter(){
        return counter;
    }

private:
    int counter;
    mutex g_Mtx;
};


int calculate(){
    Bank b;
    thread t1(&Bank::addBankAccount,&b);
    thread t2(&Bank::addBankAccount,&b);
    t1.join();
    t2.join();
    if( b.getCounter() != 2000)
        cout << "Error value is " << b.getCounter() << endl;
}

int main()
{
    for(int i = 0; i < 10000; i++)
        calculate();
    return 0;
}
互斥锁本身是必要的,以保持正确的结果。 如果没有互斥量我没有错,那会产生一些结果:

      THREAD 1                           |              THREAD 2
                                         | 
 1)  load value of counter in register   |  2) load value of counter in register
     value in register is 0              |     value in register is 0

 3)   increment register( value is 1)    |  4)    increment register( value is 1)

4) update variable, value of             |  5) update variable, value of
   counter is set to 1                          again counter is set to 1

(标记1)... 5)应指示计算机可以处理指令的顺序。因此省略一些增量。但我的问题是关于互斥锁本身。

当两个线程正在运行时,例如相同的功能

void addBankAccount(){
    unique_lock<mutex>  m ( g_Mtx );
    for( int i = 0; i < 1000; i++){
        counter++;
    }
}

在我的承诺中,当声明互斥锁并锁定锁定时,想要访问锁定数据的线程“暂停”并在解锁时“恢复”并且可以访问数据(想要使用该数据的线程在队列中)。但是当互斥锁在另一个块范围内时会发生什么?例如:

    void addBankAccount(){
        {
           unique_lock<mutex>  m ( g_Mtx );
           for( int i = 0; i < 1000; i++){
             counter++;
        }
         // some other piece of code
    }

这会改变什么吗?我已经看到了这种用法,我没有看到它与函数的原始声明有何不同。当线程想要访问被锁定的数据时,它是否“暂停”整个线程,还是仅仅“暂停”块范围,所以在这种情况下它会跳转到

 // some other piece of code

当锁被解锁时,它会跳回到范围内的循环中?

我已经阅读了很多关于互斥的文章,但我仍然对此感到困惑。

而且,我对互斥体的理解可能是错误的。

所有解释都表示赞赏。

由于

1 个答案:

答案 0 :(得分:1)

在您的示例中,没有区别。将锁嵌入内部块的原因是可以提前释放互斥锁。

void addBankAccount(){
    int count_save;
    {
       unique_lock<mutex>  m ( g_Mtx );
       for( int i = 0; i < 1000; i++){
         counter++;
       }
       count_save = counter;
     }  // mutex will be released here

     // Still inside addBankAccount, but now it's safe to do IO
     std::cout << "Bank account is now" << count_saved;
}

您经常发现要释放互斥锁,然后执行其他处理。例如,IO很慢,并涉及获取其他锁;在持有互斥锁时不要这样做是个好主意。

请注意,在示例中,count_save是一个局部变量,因此对于线程是私有的 - 它不是由互斥锁保护的共享状态的一部分。一旦互斥锁被释放,必须不要触摸任何共享状态。

另请注意,由于缺少同步,帐户状态可能会在输出发生之前发生更改。实际上,无法保证较早更改的输出将在稍后更改的输出之前发生。 (因此,这可能不是一个特别好的例子!)