使用c ++ 11的std :: thread,什么时候修改全局变量是线程安全的?

时间:2014-07-22 08:40:00

标签: c++ multithreading c++11 g++

考虑这个来源:

#include <string>
#include <iostream>
#include <thread>

using namespace std;

int *up;

void testf(){
    for(int i = 0; i < 1000; i++)
        for(int f = 0; f < 11; f++)
            up[i]++;
}

int main() {
    up = new int[1000];

    std::thread tt[7];

    for(int ts=0;ts<7;ts++) {
        tt[ts]=std::thread(testf);
    }

    for(int ts=0;ts<7;ts++) {
        tt[ts].join();
    }

    for(int i = 0; i < 1000; i++)
        cout << up[i];
    cout << endl;
    delete[] up;
    return 0;
}

我故意在没有任何互斥锁的情况下写入相同的int数组。 testf()中的for循环将int up[1000]的所有成员增加11,我们有7个线程。所以输出应该是77777777 ......(2000 Sevens)

但有时当我运行exe时,我会得到一些像这样的数字:

...7777777066676672756866667777777777777377777366667777777...

为什么会这样?

(在linux上编译:g ++ -std = c ++ 11 -pthread)

1 个答案:

答案 0 :(得分:6)

原因是&#34; up [i] ++;&#34;不是线程安全的操作。它基本上是这样的:

  1. 读取up [i]
  2. 的值
  3. 在读取值中添加一个
  4. 写出up [i]
  5. 的值

    有两个线程会发生什么:

    • Thread1 1)读取up [i](3)
    • 的值
    • Thread1 2)将一个加到读取值(4)
    • Thread1 3)写入up [i](4)

    • 的值
    • Thread2 1)读取up [i](4)

    • 的值
    • Thread2 2)将一个加到读取值(5)
    • Thread2 3)写入up [i](5)
    • 的值

    会发生什么:

    • Thread1 1)读取up [i](3)
    • 的值
    • Thread2 1)读取up [i](3)

    • 的值
    • Thread1 2)在读取值(4)

    • 中加1
    • Thread1 3)写入up [i](4)
    • 的值
    • Thread2 2)将一个加到读取值(4)
    • Thread2 3)写入up [i](4)
    • 的值

    因此两个线程都向数组写入4!

    要解决此问题,您需要对数组执行互斥或原子递增操作: http://baptiste-wicht.com/posts/2012/07/c11-concurrency-tutorial-part-4-atomic-type.html