Эти вопросы и ответы направлены на глубокое понимание тонкостей использования порядка освобождения-приобретения памяти для атомарных операций в C++.
Во-первых, я изложу свое понимание семантики освобождения-приобретения, затем я изложу свои сомнения по поводу конкретного случая параллельного программирования на C++ и, наконец, предложу более подходящий случай для иллюстрации этой концепции.
После этого сохранения порядок операций чтения или записи в текущем потоке не может быть изменен. .
По сути, это обеспечивает загрузку->сохранение и сохранение->гарантии порядка сохранения в текущем потоке.
[*]Все записи в текущем потоке видны в других потоках, которые получают ту же атомарную переменную.
Семантика подразумевает, что запись в атомарную переменную в текущем потоке видна всем потокам, которые получают одну и ту же атомарную переменную одновременно (а не индивидуально). Как только операция выпуска попадает в систему согласованности, она фактически попадает в глобальный порядок, делая ее видимой для всех потоков, а не только для некоторых.
memory_order_acquire:
Нет чтения и записи в порядок текущего потока можно изменить до этой загрузки.
По сути, это обеспечивает гарантии порядка загрузки->загрузки и загрузки->сохранения в текущем потоке. .
[*]Все записи в других потоках, которые освобождают ту же атомарную переменную, видны в текущем поток.
Любое освобождение атомарной переменной другими потоками будет отслеживаться операцией получения текущего потока (аналогично, а не только некоторым операции).
Вышеизложенное отражает мое понимание семантики выпуска-приобретения.
Мои сомнения по поводу демонстрации, объясняющей процесс выпуска-приобретения в параллельном программировании на C++ (этот случай, по-видимому, адаптирован из последовательной согласованности демо на cppreference)
Вот демо из книги, объясняющей выпуск-приобретение. В книге утверждается, что последнее утверждение сработает, но после тестирования на x86 и ARM я обнаружил, что оно никогда не срабатывает. Мои сомнения по поводу этого случая основаны не только на том, что я не смог воспроизвести результат, но и на теоретическом фундаменте, который я представил выше. Причины следующие:
Операция сохранения, соответствующая выпуску, видна всем потокам получения, а не только некоторым. Основываясь на этом понимании, должен существовать глобальный порядок (записи) для X и Y при применении к памяти, гарантирующий, что потоки c и d увидят один и тот же результат; либо x->y, либо y->x, но никогда c не видит x->y, а d видит y->x.
Вторым доказательством является то, что гарантии выпуска-приобретения:
Store->Store
Загрузить->Сохранить
Загрузить->Загрузить
Но пропускает Store->Load
Поэтому, если код в каждом потоке не использует шаблоны Store->Load, мы можем обеспечить глобальный порядок при применении к памяти.
Исходя из вышеизложенного, я думаю, что следующий пример более разумен для объяснения процесса выпуска-приобретения. Здесь для работы с атомарными переменными используется модель Release-Acquire, а семантика Store->Load создается внутри каждого потока. Поскольку Release-Acquire не гарантирует порядок Store->Load, весьма вероятно, что оба потока не смогут завершить C++, что в конечном итоге приведет к сбою утверждения.
Эти вопросы и ответы направлены на глубокое понимание тонкостей использования порядка освобождения-приобретения памяти для атомарных операций в C++. Во-первых, я изложу свое понимание семантики освобождения-приобретения, затем я изложу свои сомнения по поводу конкретного случая параллельного программирования на C++ и, наконец, предложу более подходящий случай для иллюстрации этой концепции. [list] [*] [b]Мое понимание семантики выпуска-приобретения (см. https://en.cppreference.com/w/cpp/atomic/memory_order)[/b] [/list] [b]memory_order_release:[/b] [list] [*][b]После этого сохранения порядок операций чтения или записи в текущем потоке не может быть изменен. .[/b]
По сути, это обеспечивает загрузку->сохранение и сохранение->гарантии порядка сохранения в текущем потоке. [/list]
[*][b]Все записи в текущем потоке видны в других потоках, которые получают ту же атомарную переменную.[/b] [list] Семантика подразумевает, что запись в атомарную переменную в текущем потоке видна всем потокам, которые получают одну и ту же атомарную переменную одновременно (а не индивидуально). Как только операция выпуска попадает в систему согласованности, она фактически попадает в глобальный порядок, делая ее видимой для всех потоков, а не только для некоторых. [/list]
[b]memory_order_acquire:[/b] [list] [*][b]Нет чтения и записи в порядок текущего потока можно изменить до этой загрузки.[/b]
По сути, это обеспечивает гарантии порядка загрузки->загрузки и загрузки->сохранения в текущем потоке. . [/list]
[*][b]Все записи в других потоках, которые освобождают ту же атомарную переменную, видны в текущем поток.[/b] [list] Любое освобождение атомарной переменной другими потоками будет отслеживаться операцией получения текущего потока (аналогично, а не только некоторым операции). [/list]
Вышеизложенное отражает мое понимание семантики выпуска-приобретения. [list] [*][b]Мои сомнения по поводу демонстрации, объясняющей процесс выпуска-приобретения в параллельном программировании на C++ (этот случай, по-видимому, адаптирован из последовательной согласованности демо на cppreference)[/b] [/list] [img]https://i.sstatic.net/ nSXhbRJP.jpg[/img]
Вот демо из книги, объясняющей выпуск-приобретение. В книге утверждается, что последнее утверждение сработает, но после тестирования на x86 и ARM я обнаружил, что оно никогда не срабатывает. Мои сомнения по поводу этого случая основаны не только на том, что я не смог воспроизвести результат, но и на теоретическом фундаменте, который я представил выше. Причины следующие: [list] [*]Операция сохранения, соответствующая выпуску, видна всем потокам получения, а не только некоторым. Основываясь на этом понимании, должен существовать глобальный порядок (записи) для X и Y при применении к памяти, гарантирующий, что потоки c и d увидят один и тот же результат; либо x->y, либо y->x, но никогда c не видит x->y, а d видит y->x.
[*] Вторым доказательством является то, что гарантии выпуска-приобретения:
Store->Store
[*]Загрузить->Сохранить
[*]Загрузить->Загрузить
[*]Но пропускает Store->Load
Поэтому, если код в каждом потоке не использует шаблоны Store->Load, мы можем обеспечить глобальный порядок при применении к памяти.
[/list]
[list] [*][b]Исходя из вышеизложенного, я думаю, что следующий пример более разумен для объяснения процесса выпуска-приобретения. Здесь для работы с атомарными переменными используется модель Release-Acquire, а семантика Store->Load создается внутри каждого потока. Поскольку Release-Acquire не гарантирует порядок Store->Load, весьма вероятно, что оба потока не смогут завершить C++, что в конечном итоге приведет к сбою утверждения.[/b] [/list] [img]https://i.sstatic.net/TQwc2BJj.png[/img]
Я пытаюсь создать дистрибутив на основе Debian, используя инструмент под названием live-build для действий github под управлением Ubuntu (по какой-то причине я не могу/не предпочитаю собирать локально), и получаю ошибку:
Я писал параллельный рабочий процесс для небольшого тестового проекта, который включал следующий рабочий процесс:
Существует четыре отдельные процедуры, каждая из которых принимает один параметр и возвращает одну переменную в качестве данных,...
Другой разработчик показал мне следующий фрагмент:
std::atomic_flag lock;
// ...
while (lock.test_and_set(std::memory_order::acquire)) {}
// critical section
lock.clear(std::memory_order::release);
Другой разработчик показал мне следующий фрагмент:
std::atomic_flag lock;
// ...
while (lock.test_and_set(std::memory_order::acquire)) {}
// critical section
lock.clear(std::memory_order::release);