Я второй раз смотрю на великий доклад Херба об атомном оружии и пытаюсь осмыслить концепции, которые проходят через всю историю модели памяти / последовательной согласованности. Есть одна вещь, которая беспокоит меня сейчас на концептуальном уровне. Один из выводов из разговора заключается в том, что, используя атомарные методы, мы можем намекнуть компилятору о взаимодействиях между потоками, которые иначе компилятор не смог бы обнаружить.
Поэтому я начал беспокоиться о следующем сценарии:
int local_copy_of_shared_var = shared_var;
if (local_copy_of_shared_var > some_threshold)
{
DoSomething();
}
... Do some work
if (local_copy_of_shared_var > some_threshold)
{
DoSomethingElse();
}
В этом случае, как также указал Ханс Бохем в «Как неправильно компилировать программы с «доброкачественными» гонками данных» (с именами переменных, соответствующим образом скорректированными для приведенного выше фрагмента):
Если компилятор решит, что между двумя тестами ему нужно сбросить регистр, содержащий local_copy_of_shared_var, он вполне может решить не сохранять значение (в конце концов, это всего лишь копия shared_var) и вместо этого просто перечитать значение shared_var. для второго сравнения с использованием local_copy_of_shared_var.
[...] основная проблема возникает из-за того, что компилятор использует предположение, что значения переменных не могут изменяться асинхронно без явного присваивания. Такое предположение вполне правомерно, если гонки данных запрещены спецификацией языка, как в нашем случае. Такие асинхронные изменения невозможны при отсутствии гонки данных.
Теперь, поскольку atomics (с порядком памяти по умолчанию seq_cst) должна гарантировать отсутствие гонок данных и поскольку они являются подсказкой компилятору о взаимодействии таких переменных между различными потоками, можно ли утверждать, что использование atomics в предыдущем фрагменте запретить компилятору вставлять такое повторное чтение из shared_var и вместо этого рассматривать local_copy_of_shared_var как одноразовый снимок, избегая несоответствия между двумя тестами?
Я думаю, что у меня есть что-то неправильное в моих рассуждениях, потому что, руководствуясь здравым смыслом, я бы не подумал, что, просто используя здесь атомарность, я могу гарантировать, что компилятор примет меры, чтобы local_copy_of_shared_var не получать обновления между двумя тестами. С другой стороны, как говорит Херб в своем выступлении, модель памяти теперь гарантирует, что компиляторы не будут добавлять ложные операции с памятью при использовании атомарных операций, что (рассматривая этот случай как ложное чтение) снова предполагает, что этот пример теперь сейф. Я очень запутался и хотел бы услышать мнение сообщества и, возможно, получить исправление, если в моих рассуждениях есть какая-то ошибка.