у меня есть std::vector
перед параллельным циклом std::pair<Object, bool>
, Все bools инициализируются true
, Цикл примерно такой:
for (int x = 0; x < xMax; ++x) // can parallelising the loop in x cause a data race?
for (int y = 0; y < yMax; ++y)
for (auto& i : vector)
if (i.first.ConstantFunctionDependingOnlyOnInput(x, y))
i.second = false;
Так как мы только устанавливаем bool вfalse
Я не вижу, что это вызывает гонку данных, но я не доверяю своей интуиции в многопоточности. Операции, выполненные в результате этого bool, впоследствии выполняются в одном потоке (стираются все элементы, где bool == true
в векторе с использованием стандартных алгоритмов.
Совет здесь будет оценен. Я собирался использовать std::atomics
но, конечно, они не могут быть использованы в std::vector
так как они не копируемы.
Ура!
Вот пример того, как это может потерпеть неудачу, и реальный код провалился именно так.
for (auto& i : vector)
if (i.first.ConstantFunctionDependingOnlyOnInput(x, y))
i.second = false;
Компилятор может оптимизировать этот код следующим образом:
for (auto& i : vector);
{
bool j = i.second;
bool k = i.first.Function(x, y);
i.second = k ? false : j;
}
Это может привести к тому, что один поток перезапишет результаты другого потока. Это может быть законной оптимизацией, потому что безусловная запись может быть дешевле, чем условная, поскольку она не может быть ошибочно предсказана.
Вы правы — это будет вести себя точно так, как вы ожидаете (без гонки данных) в любой реальной системе. В то время как официально неопределенное поведение в соответствии со стандартом C ++, реальные системы не работают таким образом. ВотЭто ответ на более широкий вопрос, который включает в себя этот.
Вот текст из стандарта, который говорит, что это официально не определено, хотя:
Два выражения выражения конфликтуют, если один из них модифицирует воспоминание
местоположение (1.7) и другое доступ или изменение та же память
место нахождения.
Если вы хотите стандартную гарантированную безопасность, вы можете рассмотреть атомное доступ к памяти.