Код: Выделить всё
#include
#include
#include
int main() {
std::atomic strong = {3};
std::atomic weak = {1};
auto t1 = std::thread([&]() {
int expected = 1;
if (weak.compare_exchange_strong(expected, 255,
std::memory_order::acquire,
std::memory_order::relaxed) == true) {
bool unique = strong.load(std::memory_order::acquire) == 1; // #1
weak.store(1, std::memory_order::relaxed); // #4
assert(unique == false);
}
});
auto t2 = std::thread([&]() {
auto val = weak.load(std::memory_order::relaxed);
while (true) {
if (val == 255) {
std::this_thread::yield();
val = weak.load(std::memory_order::relaxed);
continue;
}
if (weak.compare_exchange_strong(
val, val + 1, std::memory_order::acquire,
std::memory_order::relaxed) == true) {
break;
}
}
strong.fetch_sub(1, std::memory_order::release); // #2
});
auto t3 = std::thread([&]() {
auto val = weak.load(std::memory_order::relaxed);
while (true) {
if (val == 255) {
std::this_thread::yield();
val = weak.load(std::memory_order::relaxed);
continue;
}
if (weak.compare_exchange_strong(
val, val + 1, std::memory_order::acquire,
std::memory_order::relaxed) == true) {
break;
}
}
strong.fetch_sub(1, std::memory_order::release); // #3
});
t1.join();
t2.join();
t3.join();
}
Если вычисление значения A атомарного объекта M происходит до операции B, которая изменяет M, то A берет свое значение из побочного эффекта X на M, где X предшествует B в порядке модификации M.
Код: Выделить всё
#1Значение атомарного объекта M, определенное оценкой B, представляет собой значение, сохраненное неким неуказанным побочным эффектом A, который изменяет M, где B не происходит до A.
В более общем смысле, любой поток, утверждающий, что его операция RMW на Strong будет прочитана #1 невозможно, поскольку его операция CAS на слабом не ожидает 255, а #4 не виден для части загрузки, поэтому его цикл не может выйти.
Итак, #0 не может прочитать 1 и 2; однако он может прочитать только начальное значение 3. Верен ли мой анализ? На самом деле, это упрощенный вопрос из моего исследования реализации Arc в Rust, в частности, относительно метода is_unique (строка 2585) и метода понижения версии (строка 1735). Если цель, как описано в комментарии, состоит в том, чтобы проверить, содержит ли поток уникальный сильный, я думаю, что порядок памяти, используемый для этого случая, является чрезмерно строгим, а порядок памяти для слабого хранилища, который записывает 1, может быть, по крайней мере, ослаблен, IIUC.
Подробнее здесь: https://stackoverflow.com/questions/798 ... ther-threa
Мобильная версия