Полезна ли на практике концепция последовательности выпуска? - PullRequest
3 голосов
/ 08 мая 2019

Атомная семантика C / C ++ гарантирует только видимость (через отношение «случай до») операций памяти, выполняемых последним потоком, который выполнил «простую» операцию записи (без чтения-изменения-записи). (Существует строгая семантическая дискриминация между операциями записи и RMW.)

Рассмотрим

int x, y;
atomic<int> a;

Тема 1:

x = 1;
a.store(1,memory_order_release);

Тема 2:

y = 2;
if (a.load(memory_order_relaxed) == 1))
  a.store(2,memory_order_release);

Тогда наблюдение a == 2 подразумевает видимость операций потока 2 (y == 2), но не потока 1 (невозможно даже прочитать x).

Насколько мне известно, в реальных реализациях многопоточности используются концепции заборов (и иногда релиз-хранилище), но не происходит до-или-релиз-последовательность, которые являются концепциями высокого уровня C / C ++; Я не могу понять, с какими деталями реального оборудования соответствуют эти концепции.

Как реальная реализация не может гарантировать видимость операций с памятью потока 1, когда значение 2 в a является глобально видимым?

Другими словами, есть ли польза в определении последовательности выпуска? Почему последовательность выпуска не распространяется на каждую последующую модификацию в порядке модификации?

Рассмотрим, в частности, глупую нить 3:

if (a.load(memory_order_relaxed) == 2))
  a.store(2,memory_order_relaxed);

Может ли silly-thread 3 подавить какие-либо гарантии видимости на любом реальном оборудовании? Другими словами, если значение 2 является глобально видимым, как сделать его снова глобально видимым, чтобы нарушить любой порядок?

Не верна ли моя ментальная модель реальной многопроцессорности? Может ли значение, частично видимое, на одном процессоре, но отметить другое?

(Конечно, я предполагаю ненормальную семантику для расслабленных записей, поскольку записи, которые уходят в прошлое, делают семантику языка C / C ++ абсолютно бессмысленной, в отличие от безопасных языков, таких как Java, которые всегда имеют ограниченную семантику. Ни одна реальная реализация не может иметь сумасшедших не причинно-следственная расслабленная семантика.)

1 Ответ

1 голос
/ 08 мая 2019

Давайте сначала ответим на ваш вопрос:

Почему бы последовательность выпуска не распространяться на каждую последующую модификацию в порядке модификации?

Потому что если так, то мыпотеряет некоторую потенциальную оптимизацию.Например, рассмотрим поток:

x = 1;                            // #1
a.store(1,memory_order_relaxed);  // #2

В соответствии с текущими правилами компилятор может изменить порядок №1 и №2.Однако после расширения release-sequence компилятору не разрешается переупорядочивать две строки, потому что другой поток, такой как ваш поток 2, может вводить последовательность освобождения, возглавляемую # 2 и сопровождаемую операцией release, поэтому возможно, что некоторые читаютОперация -acquire в другом потоке будет синхронизирована с # 2.


Вы приводите конкретный пример и утверждаете, что все реализации приведут к определенному результату, в то время как языковые правила не гарантируют этот результат.Это не проблема, потому что языковые правила предназначены для обработки всех случаев, а не только вашего конкретного примера.Конечно, языковые правила могут быть улучшены, чтобы гарантировать ожидаемый результат для вашего конкретного примера, но это не тривиальная работа.По крайней мере, как мы уже говорили выше, простое расширение определения для release-sequence не является приемлемым решением.

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