c++ - 互斥锁和 block 作用域

标签 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

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

当两个线程同时运行时,例如同一个函数

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

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

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

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

 // some other piece of code

当锁被解锁时,它会跳回作用域内的循环吗?

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

还有 ofc,我对互斥量的理解可能是错误的。

感谢所有解释。

谢谢

最佳答案

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

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 是一个局部变量,因此是线程私有(private)的 - 它不是受互斥锁保护的共享状态的一部分。一旦互斥锁被释放,就不要触及任何共享状态,这一点很重要。

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

关于c++ - 互斥锁和 block 作用域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42472031/

相关文章:

c++ - 无法在 C++ 中重载 Dot '.' 运算符

c++ - 在 C++ 中进行事件处理的正确方法是什么?

c++ - 我们需要多少个内存屏障来实现 Peterson 锁?

multithreading - 如何在 Golang 中并发读取和写入文件?

c++ - 互斥锁操作是否应该因锁定两次而引发 system_error?

android - 如何从 C++ 为我的 .so 共享库调用 LoadLibrary

c++ - 错误 : ‘memset’ was not declared in this scope

c++ - boost::process 在 Cygwin 中不起作用

c++ - 为什么这段代码不能用 clang 构建,用 gcc 崩溃,但用 VC++ 运行良好?

java - AtomiceInteger 没有按 forjointask 的预期增加