Атомарные операции с одной переменной
Каковы возможные окончательные результаты для переменной x
в следующем фрагменте кода C++? (ответьте, исходя из того, что разрешено стандартом C++, а не того, что в настоящее время доступно на разных платформах)
// Inside Thread 0
std::atomic<int> x = {2};
// Inside Thread 1
x.fetch_sub(1,std::memory_order_relaxed)
// Inside Thread 2
x.fetch_sub(1,std::memory_order_relaxed)
В идеале хочу x
быть нулем в конце. Так ли это, хотя я используюstd::memory_order_relaxed
?
Изменить: чтобы сделать вопрос более точным, гарантируется ли, что 1) в потоках 1 и 2 возвращаемое значение равно 0 или 1, и 2) возвращаемое значение в потоках 1 и 2 отличается.
1 ответ
Краткий ответ: да.
Длинный ответ: std::memory_order_relaxed
описывается как:
Упрощенная операция: нет ограничений на синхронизацию или упорядочение, накладываемых на другие операции чтения или записи, гарантируется только атомарность этой операции.
Фактически это означает, что он гарантирует только атомарность. Это означает, чтоstd::atomic::fetch_sub
операция гарантирует только атомарную операцию чтения-изменения-записи, без какого-либо упорядочивания в отношении других операций. Это, однако, не означает, что компилятор может переупорядочить две разные атомарные операции чтения, изменения и записи (что может привести к гонке данных, что является неопределенным поведением). Они все еще атомарны.
В идеале хочу
x
быть нулем в конце. Так ли это, хотя я используюstd::memory_order_relaxed
?
Порядок памяти в этом случае не имеет значения. Ни один из них не помешает основным гарантиям атомарности. Сделанное вами выше утверждение будет справедливо для любого порядка памяти, потому что оно по определению истинно для любой атомарной переменной, которая изменяется таким образом (два, потенциально асинхронных, вычитания из начального значения2
).
Чтобы сделать вопрос более точным, гарантируется ли, что 1) В обоих потоках возвращаемое значение либо
0
или1
и 2) Возвращаемое значение в потоках1
а также2
разные.
Да и да, если потоки возвращают значение, котороеx
держится сразу после fetch_sub
вызов, который, вероятно, технически неверен (потоки не возвращают значения), но я вижу, откуда вы идете.