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

0

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

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

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

...7777777066676672756866667777777777777377777366667777777...

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

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

  • 4
    Ваш код имеет гонку данных и, следовательно, неопределенное поведение.
  • 1
    И название вопроса крайне вводит в заблуждение. Вы никогда не обращаетесь к объекту std::thread одновременно, поэтому вопрос вовсе не в безопасности потока std::thread .
Показать ещё 5 комментариев
Теги:
multithreading
c++11
g++

1 ответ

6
Лучший ответ

Причина в том, что "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

  • 1
    Это возможное (и даже вероятное) объяснение того, что на самом деле происходит в его непосредственной программе, но реальный ответ более общий: если к объекту обращаются более одного потока и что-либо изменяют, все обращения к нему (не только записи) должны быть синхронизированы, или происходит неопределенное поведение.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню