Я прочитал много постов и посмотрел несколько видео на Youtube с атомарной моделью C ++ и моделью памяти (ConCpp 17, 14).
Когда я читаю книгу Параллельность в действии , раздел 5.3.3, СМЕШАННЫЙ ЗАКАЗ , я до сих пор не могу понять пример, представленный автором под его предположениями.
Предположения автора
Дело не только в том, чтоКомпилятор может изменить порядок инструкций. Даже если потоки выполняют один и тот же бит кода , они могут расходиться во мнениях относительно порядка событий из-за операций в других потоках в отсутствие явных ограничений на порядок, поскольку могут храниться разные кэши ЦП и внутренние буферы.разные значения для одной и той же памяти.Это так важно, я скажу это снова: потоки не должны согласовывать порядок событий.Вы должны не только выбросить ментальные модели, основанные на операциях чередования, вы также должны выбросить ментальные модели, основанные на идее переупорядочения команд компилятором или процессором.
Предположим, что код, который мы видим, не переупорядочен .
Пример кода:
#include <atomic>
#include <thread>
#include <assert.h>
std::atomic<bool> x,y;
std::atomic<int> z;
void write_x_then_y()
{
x.store(true,std::memory_order_relaxed); // 1
y.store(true,std::memory_order_relaxed); // 2
}
void read_y_then_x()
{
while(!y.load(std::memory_order_relaxed)); // 3
if(x.load(std::memory_order_relaxed)) // 4
++z;
}
int main() {
x=false;
y=false;
z=0;
std::thread a(write_x_then_y);
std::thread b(read_y_then_x);
a.join();
b.join();
assert(z.load()!=0); // 5
}
по этой ссылке: https://www.developerfusion.com/article/138018/memory-ordering-for-atomic-operations-in-c0x/
Почему x.load(relaxed)
возврат false
но y.load(relaxed)
возврат true
?
Вывод автора
На этот раз assert (5) может срабатывать, потому что загрузка x (4) может читать false, даже если загрузка y (3)) читает true и сохранение x (1) происходит до сохранения y (2). x и y являются разными переменными, поэтому нет никаких гарантий упорядочения, связанных с видимостью значений, возникающих в результате операцийна каждом.
Q.Почему загрузка x может быть ложной?
Автор приходит к выводу, что assert может срабатывать.Итак, z
может быть 0
.Итак, if(x.load(std::memory_order_relaxed))
: x.load(std::memory_order_relaxed)
равно false
.
Но в любом случае, while(!y.load(std::memory_order_relaxed));
делает y
true
.
Если мы не переупорядочим последовательность кода(1) и (2), как это возможно, что y
истинно, но x
все еще не сохраняется?
Как понять рисунок, предоставленныйавтор?
На основании the store of x (1) happens-before the store of y (2)
, если x.store(relaxed)
произойдет раньше y.store(relaxed)
, x
должно быть true
сейчас.Но почему x
все еще false
, даже y
это true
?