Допустимо ли использовать memory_order_release для атомарной загрузки?
Нет. Для атомарной загрузки порядок memory_order_release недопустим: стандарт C++ объявляет такое использование неопределённым поведением. Загрузка может иметь порядок relaxed, acquire или seq_cst, но не release.
Модель памяти появилась в стандарте C++11, чтобы формально описать взаимодействие потоков без привязки к конкретному процессору. Она разделяет две разные задачи: публикацию ранее выполненных операций и наблюдение за опубликованными операциями.
memory_order_release предназначен для операции, которая публикует изменения другим потокам, обычно для атомарной записи. memory_order_acquire предназначен для операции, которая получает публикацию, обычно для атомарного чтения.
Атомарная загрузка только читает значение. Она не может сообщить другим потокам, что операции текущего потока должны стать видимыми, поэтому семантика release к ней неприменима.
Попытка передать memory_order_release в load не превращает загрузку в более сильную операцию и не является альтернативной формой acquire. Это нарушение требований к допустимым порядкам памяти и потенциальный источник неопределённого поведения.
Для атомарной загрузки допустимы следующие основные варианты:
relaxed — гарантирует атомарность самой загрузки, но не устанавливает межпоточную видимость обычных данных;acquire — запрещает перемещать последующие операции чтения и записи перед загрузкой и может получить эффект публикации от соответствующей операции release;seq_cst — добавляет гарантии последовательной согласованности и обычно является самым строгим вариантом.Для атомарной записи допустимы relaxed, release и seq_cst. Порядок release означает: если другой поток выполнит согласованную загрузку acquire и увидит значение, опубликованное этой записью, то действия до записи release будут происходить до действий после загрузки acquire.
Минимальная схема публикации выглядит так:
Здесь release находится на записи, потому что производитель публикует data, а acquire — на загрузке, потому что потребитель принимает публикацию. Замена загрузки на relaxed убрала бы необходимую связь видимости, а замена на release была бы недопустима.
memory_order_acq_rel также нельзя применять к обычной атомарной загрузке или записи: это комбинированный порядок для атомарных операций, которые одновременно читают и изменяют значение, например для некоторых RMW-операций. Для простых load и store нужно выбирать порядок из множества, допустимого для конкретного вида операции.
В очереди сообщений разработчик решил использовать release при чтении флага готовности, считая, что это «максимально сильная» настройка. Такой выбор не создаёт корректной публикации и нарушает требования модели памяти.
Вариант с seq_cst технически решает задачу, если использовать его корректно, но может добавить ненужные ограничения на переупорядочивание операций. Вариант с relaxed дешевле, однако не обеспечивает видимость обычных полей сообщения.
Правильное решение — запись флага с release, а чтение флага с acquire. Оно выражает направление передачи данных и обычно даёт необходимые гарантии без избыточной глобальной упорядоченности. В результате потребитель безопасно читает сообщение после успешного наблюдения опубликованного флага.
release на seq_cst на атомарной загрузке?Нет: seq_cst для загрузки допустим, но он не исправляет ошибку автоматически, если публикация данных организована неправильно. Должна существовать согласованная схема: поток-производитель выполняет запись данных до атомарной операции публикации, а поток-потребитель после загрузки seq_cst получает эту публикацию. Усиление только одной стороны не заменяет анализ отношения happens-before.
memory_order_acquire атомарность обычных данных?Нет. Acquire не делает обычную переменную атомарной и не разрешает конкурентную запись и чтение одного поля без синхронизации. Он обеспечивает упорядочивание и видимость уже выполненных операций только при наличии соответствующей синхронизации с операцией release; сами обращения к данным всё равно должны быть организованы без гонки данных.
memory_order_relaxed для загрузки флага, если флаг сам атомарный?Атомарность флага сохранится, но этого недостаточно для публикации связанных обычных данных. Потребитель может атомарно увидеть новое значение флага, не получив требуемой гарантии видимости записей, которые производитель сделал до установки флага. relaxed подходит, когда важна только атомарная переменная и её порядок относительно обычных данных не используется.