Возможно ли, что утверждение может завершиться неудачно с помощью Memory_order::relaxed для передачи указателей?C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Возможно ли, что утверждение может завершиться неудачно с помощью Memory_order::relaxed для передачи указателей?

Сообщение Anonymous »

Рассмотрим этот пример:

Код: Выделить всё

#include 
#include 
#include 
#include 

int main(){
std::atomic val = 1;
std::atomic ptr;
auto t1 = std::thread([&](){
auto v = val.load(std::memory_order::relaxed);
while(true){
if(v==-1){
v = val.load(std::memory_order::relaxed);
continue;
}
if(val.compare_exchange_strong(v,v+1,std::memory_order::acquire,std::memory_order::relaxed)==true){
break;
}
}
ptr.store(&val,std::memory_order::relaxed);  // #1
});
auto t2 = std::thread([&ptr](){
std::atomic* val_ptr = ptr.load(std::memory_order::relaxed); // #2
while(val_ptr==nullptr){
val_ptr = ptr.load(std::memory_order::relaxed);  // #3
}
int v = 1;
bool r = val_ptr->compare_exchange_strong(v,-1,std::memory_order::acquire,std::memory_order::relaxed); // #4
assert(r==false);  // #5
});
t1.join();
t2.join();
}
Может ли утверждение №5 никогда не давать сбой, даже если №1 и №2/ использовать расслабленный порядок? Утверждение не выполняется, только если #4 возвращает true; это означает, что #4 выполнена успешно, то есть операция RMW загружает 1 и записывает -1. Модификация, значение которой равно 1, является лишь начальным значением атомарного объекта val. В этой программе все операции с атомарным объектом val являются либо операциями RMW, либо чистой загрузкой (т. е. сбой cas). Таким образом, все эти операции сериализуются в соответствии с [atomics.order] p10

Атомарные операции чтения-изменения-записи всегда должны считывать последнее значение (в порядке модификации), записанное перед записью, связанной с операцией чтения-изменения-записи.

То есть никакие две операции RMW не могут прочитать одну и ту же модификацию. Если #4 считывает начальное значение, то операции CAS не должны завершиться успешно, и это просто чистая загрузка. Не уверен, что следующий анализ является формальным:
  • в t1 не будет достигнут, если v равен -1, что приводит к невозможности выхода из цикла
  • Код: Выделить всё

    CASСбои 
    приводят к тому, что цикл не завершается, и возвращаемся к вышеизложенному
То есть цикл завершится только в том случае, если CAS загрузит 1 и запишет 2 в этой программе. Однако предполагается, что #4 загружает 1 и записывает -1, поэтому цикл в t1 не может выйти из программы, что приводит к невозможности достижения #1. Цикл в t2 не может завершиться, если загрузка читает nullptr. То есть #5 может быть достигнут только в том случае, если цикл в t2 существует, что требует наличия какого-либо побочного эффекта, отличного от nullptr. В этой программе побочным эффектом создания указателя, отличного от nullptr, может быть только #1; он не будет достигнут в этой программе с учетом этого предположения, поэтому побочный эффект не будет выполнен где-то за время существования программы и, следовательно, он не может существовать. Таким образом, #2 и #3 не могут читать #1, иначе это нарушит [intro.races] p10

Значение атомарного объекта M, определенное оценкой B, представляет собой значение, сохраненное неким неуказанным побочным эффектом A, который модифицирует M, где B не происходит раньше A.

Таким образом, утверждение никогда не может потерпеть неудачу. Верен ли мой анализ?

Подробнее здесь: https://stackoverflow.com/questions/798 ... to-transfe
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»