Отношение «Синхронизируется с»

Из статьи cppreference на std::memory_order:

Синхронизируется с: Если атомарное сохранение в потоке A является операцией освобождения, атомарная загрузка в потоке B из той же переменной является операцией получения, а загрузка в потоке B считывает значение, записанное хранилищем в потоке A, то хранилище в потоке А синхронизируется с нагрузкой в ​​потоке Б.

Имеет ли фраза «…читает значение, написанное…» точное значение, которое мне не хватает?

Слова до и после важны: «загрузка... читает значение, записанное хранилищем». Здесь поток B загружает/получает сохраненное/освобождает значение и видит новое значение, поэтому синхронизируется; после загрузки поток B может безопасно прочитать все данные, записанные потоком A перед сохранением. Если хранилище не было «освобождено» или загрузка не была «получена», обновление данных может появиться в потоке B в любом порядке.

dalfaB 22.07.2024 00:10
preshing.com/20120913/acquire-and-release-semantics — хорошее объяснение на простом английском языке концепций/функций оборудования, которые формализм C++ предоставляет программистам. Другие статьи Прешинга о программировании без блокировок превосходны, и их гораздо проще понять, чем просто формализм C++. Как только вы узнаете, какие вещи включают в себя атомы без блокировок, вам станет легче понять, как устроен формализм.
Peter Cordes 22.07.2024 02:40
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
67
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Каждый атомарный объект имеет (индивидуально) общий порядок своих модификаций, так называемый порядок модификации, который все потоки должны глобально согласовать.

Каждый побочный эффект (т. е. сохранение) атомарного объекта составляет запись в этом порядке модификации.

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

Эти правила согласованности приведены на странице cppreference, на которую вы ссылаетесь:

Следующие четыре требования гарантируются для всех атомарных операций:

  1. Согласованность записи-записи: если оценка A, которая изменяет некоторый атомарный M (запись) происходит - до оценки B, которая изменяет M, затем появляется A раньше, чем B, в порядке модификации M.

  2. Когерентность чтения-чтения: если вычисление значения A некоторого атома M (a чтение) происходит — до вычисления значения B на M, и если значение A происходит в результате записи X на M, то значение B является либо значением сохраненное X, или значение, сохраненное побочным эффектом Y на M, которое появляется позже, чем X, в порядке модификации M.

  3. Когерентность чтения-записи: если вычисление значения A некоторого атомарного M (a чтение) происходит — перед операцией B над M (записью), тогда значение A возникает в результате побочного эффекта (записи) X, который появляется раньше, чем B в порядок внесения изменений М.

  4. Согласованность записи-чтения: если побочный эффект (запись) X на атомном происходит объект M — до вычисления значения (чтения) B из M, тогда Оценка B должна принимать свое значение от X или от побочного эффекта Y, который следует за X в порядке модификации M.

Обратите внимание, что вышеприведенное использует неформальный язык, такой как «значение A берется из», что формально должно быть «вычисление значения A берет свое значение из». Официальную спецификацию можно найти в [intro.races]/14 и последующих параграфах.

«и загрузка в потоке B считывает значение, записанное хранилищем в потоке A» — это также менее формальный способ сказать «и вычисление значения в потоке B берет свое значение из побочного эффекта в потоке A в порядке модификации атомный объект».

В вашей цитате говорится, что отношение синхронизируется с возникает только при конкретной оценке, которая вызвала побочный эффект для атомарного объекта, из которого вычисление значения берет свое значение.

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


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

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

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

Но из-за некоторых необычных моделей памяти ЦП это не применимо ко всем операциям предыдущих выпусков. Текущее определение последовательности релизов можно найти в [intro.races]/5, и по этому поводу ведутся (постоянные?) дискуссии. В частности, текущее определение содержит только операции освобождения, которые также являются операциями чтения-изменения-записи.

Наивно можно было бы ожидать, что отношениеsyncs-with будет применяться ко всем предыдущим хранилищам релизов в порядке модификации, поэтому это может привести к некоторым неожиданным результатам.

Например, рассмотрим этот сценарий:

  • атомарная переменная начинается со значения 0
  • поток 1 сохраняет 1 в него после записи некоторых данных A для публикации
  • поток 2 ожидает, пока состояние атомарной переменной станет 1 с ослабленным порядком памяти, затем записывает (в другом месте) некоторые другие данные B для публикации и выпуска-сохранения 2 в атомарную переменную (не с приращением RMW!).
  • поток 3 приобретает — загружает значение 2 из хранилища потока 2.

Тогда поток 3 сможет безопасно получить данные B, но поскольку модификация, не связанная с RMW, не является частью последовательности выпуска, никакой синхронизации с потоком 1 не будет, и доступ к данным A будет представлять собой гонку данных.

Интересный факт: на большинстве реального оборудования загрузка получения синхронизируется со всеми операциями более раннего выпуска в порядке модификации. Но по крайней мере в одном (я думаю, PowerPC) есть крайний случай, когда это не так, поэтому (в позднем проекте C++11) они ослабили правила синхронизации, чтобы синхронизироваться только с последовательностью релизов (хранилище релизов). и любое количество атомных RMW). Что означает «последовательность релизов»? . И open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0668r1.html указывает, что текущее определение не идеально подходит для программистов или архитекторов ЦП.

Peter Cordes 22.07.2024 00:36

Другие вопросы по теме