Использование С++ 11 std :: thread, когда изменяет глобальные переменные потокобезопасными?

Рассмотрим этот источник:

#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;
}
</thread></iostream></string>

Я намеренно записываю в тот же массив int без каких-либо мьютексов. Цикл for в testf() будет увеличивать все элементы int up[1000] на 11, и у нас есть 7 потоков. Таким образом, выход должен быть 77777777... (2000 Sevens)

Но иногда, когда я запускаю exe, я получаю патч чисел вроде этого:

...7777777066676672756866667777777777777377777366667777777...

Почему это происходит?

(для компиляции по linux: g++ -std = С++ 11 -pthread)

1 ответ

Причина в том, что "up [i] ++;" не является безопасным потоком. В основном это происходит:

  1. read value up [i]
  2. добавьте один к значению чтения
  3. записать значение up [i]

С двумя потоками, что должно произойти:

  • 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)

  • 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

licensed under cc by-sa 3.0 with attribution.