Применяются ли для std :: mutex гарантии видимости релиза-приобретения только к критическому разделу? - PullRequest
4 голосов
/ 20 сентября 2019

Я пытаюсь понять эти разделы под заголовком Релиз-Приобретение заказа https://en.cppreference.com/w/cpp/atomic/memory_order

Они говорят об атомной нагрузке и хранилищах:

Если атомарное хранилище в потоке A помечено memory_order_release, а атомарная загрузка в потоке B из той же переменной помечена memory_order_acquire, все записи в память (не атомарные и расслабленные атомарные) произошли до атомарного хранилища с точки зрения потокаA, становятся видимыми побочные эффекты в потоке B. То есть, как только атомная загрузка будет завершена, поток B гарантированно увидит все записи потока A в память.

Тогда относительно мьютексов:

Блокировки взаимного исключения, такие как std :: mutex или атомная спин-блокировка, являются примером синхронизации освобождения-захвата: когда блокировка освобождается потоком A и приобретается потоком B, все, что происходило в критическойраздел (перед выпуском) в контексте потока A должен быть виден потоку B (после получения), которыйвыполняет ту же критическую секцию.

Первый абзац, кажется, говорит, что атомная загрузка и хранение (с memory_order_release, memory_order_acquire) потока B гарантированно увидят все Тема А написал.включая неатомарную запись.

Второй абзац, по-видимому, предполагает, что мьютекс работает точно так же, , за исключением , область видимости B ограничена тем, что было заключено в критическуюраздел, это точная интерпретация?или каждая запись, даже перед критической секцией, будет видна B?

Ответы [ 2 ]

2 голосов
/ 21 сентября 2019

Я думаю, что причина, по которой цитата cppreference о мьютексах написана таким образом, заключается в том, что если вы используете мьютексы для синхронизации, все общие переменные, используемые для связи, всегда должны быть доступны внутри критической секции.

Стандарт 2017 года говорит в 4.7.1:

вызов, который получает мьютекс, будет выполнять операцию получения в местоположениях, включающих мьютекс.Соответственно, вызов, который освобождает тот же мьютекс, будет выполнять операцию освобождения в тех же местах.Неформально выполнение операции освобождения A приводит к тому, что предшествующие побочные эффекты в других областях памяти становятся видимыми для других потоков, которые впоследствии выполняют операцию потребления или получения для A.

Обновление: Я хочу убедиться, что у меня есть солидный пост, потому что на удивление трудно найти эту информацию в Интернете.Спасибо @Davis Herring за указание на правильное направление.

Стандарт гласит:

в 33.4.3.2.11 и 33.4.3.2.25 :

разблокировка мьютекса синхронизируется с последующими операциями блокировки, которые получают владение тем же объектом

(https://en.cppreference.com/w/cpp/thread/mutex/lock, https://en.cppreference.com/w/cpp/thread/mutex/unlock)

в 4.6.16 :

Каждое вычисление значения и побочный эффект, связанный с полным выражением, секвенируется перед каждым значениемвычисление и побочный эффект, связанный со следующим полным выражением, которое будет оценено.

https://en.cppreference.com/w/cpp/language/eval_order

in 4.7.1.9 :

Оценка A между потоками происходит до оценки B, если

4.7.1.9.1) - A синхронизируется с B, или

4.7.1.9.2) - A упорядочен по зависимости перед B, или

4.7.1.9.3) - для некоторой оценки X

4.7.1.9.3.1) ------A синхронизируется с X, а последовательность X перед B или

4.7.1.9.3.2) ------ A секвенируется до того, как X и X-поток происходит до B, или

4.7.1.9.3.3) ------ A inter-поток происходит до того, как X и X-потоки происходят до B.

https://en.cppreference.com/w/cpp/atomic/memory_order

  • Таким образом, разблокировка мьютекса B inter-thread происходит до последующая блокировка C на 4.7.1.9.1.
  • Любая оценка A, которая происходит в программном порядке до разблокировки мьютекса B, также inter-thread происходит до C на 4.7.1.9.3.2
  • Поэтому после unlock() гарантирует, что все предыдущие записи, даже те, которые находятся вне критической секции, должны быть видимы для совпадающего lock().

Этот вывод согласуется скак мьютексы реализованы сегодня (и были в прошлом), так что все программный порядок предыдущих загрузок и хранилищ завершаются перед разблокировкой.(Точнее, магазины должны быть видны до того, как будет видна разблокировка, когда наблюдается соответствующая операция блокировки в любом потоке.) Нет сомнений, что это является общепринятым определением выпуска в теории и на практике.

1 голос
/ 21 сентября 2019

Здесь нет ничего волшебного: секция мьютекса просто описывает общий случай, когда (поскольку каждое посещение критической секции может записывать общие данные) рассматриваемый писатель защищает весь свой доступ с мьютексом.(Другие, более ранние записи видны и могут иметь значение: рассмотрите возможность создания и инициализации объекта без синхронизации, а затем сохранения его адреса в общей переменной в критическом разделе.)

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