Как понять RELAXED ORDERING в std :: memory_order (C ++) - PullRequest
1 голос
/ 15 апреля 2019

Я прочитал много постов и посмотрел несколько видео на 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/

enter image description here

Почему 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?

1 Ответ

2 голосов
/ 15 апреля 2019

Вы и друг оба согласны, что x=false и y=false.Однажды вы отправляете ему письмо с сообщением, что x=true.На следующий день вы отправляете ему письмо с сообщением, что y=true.Вы определенно отправляете ему письма в правильном порядке.

Через некоторое время ваш друг получает от вас письмо с сообщением, что y=true.Теперь, что твой друг знает о x?Он , вероятно, уже получил письмо, в котором ему сообщалось x=true.Но, возможно, почтовая система временно потеряла его, и он получит его завтра.Поэтому для него x=false и x=true являются действительными возможностями, когда он получает письмо y=true.

Итак, обратно в кремниевый мир.Память между потоками имеет никаких гарантий на все, что записи из других потоков появляются в любом конкретном порядке, и поэтому «задержанный x» вполне возможен.Все, что добавляет atomic и использует relaxed, это останавливает два потока, участвующих в одной переменной, в неопределенное поведение. не дает никаких гарантий на заказ. Вот для чего нужны более сильные порядки.

Или, чуть более грубо, вот мои навыки MSPaint:

enter image description here

В этом случае фиолетовая стрелка, которая является потоком 'x' из первого потока во второй поток, приходит слишком поздно, тогда как зеленая стрелка (пересечение y) происходит быстро.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...