Получение и добавление заказа

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

Предположим, что переменная содержит 0. Поток A использует __atomic_fetch_and_add для увеличения переменной и каким-то образом уведомляет поток B. В ответ поток B использует __atomic_fetch_and_add для уменьшения значения той же переменной, возвращая ее к 0. Таким образом, кажется, что переменная должна перейти от 0 до 1 и обратно. Гарантируется ли, что другой поток C не увидит добавления, выполняемые в обратном порядке, от 0 до -1 и обратно?

Да, это гарантировано. Если C выполняет случайные атомные нагрузки, он может видеть изменение переменной только в том же порядке.

curiousguy12 12.10.2018 03:58

@ curiousguy12, не могли бы вы процитировать надежный источник, чтобы обновить этот комментарий до ответа?

dfeuer 12.10.2018 04:41
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать 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
150
1

Ответы 1

Я просто перечитал этот вопрос, добавив некоторые дополнительные разъяснения, и понял, что предполагал C11, в то время как ваш вопрос, похоже, использует встроенные компоненты компилятора. С этой точки зрения, если все ваше использование memorder - это __ATOMIC_SEQ_CST, нет случая, в котором вы можете наблюдать значение -1 по тем же причинам, которые я подробно описываю ниже (из C11).

TL; DR: Это зависит от обстоятельств, но вам придется действительно выстрелить себе в ногу, чтобы такое поведение не было гарантировано. Ниже следует объяснение того, почему это мог происходит, как это могло произойти, и почему вы вряд ли столкнетесь с этим.

Гарантируется, что атомарные операции имеют глобальный порядок, но этот глобальный общий порядок не определен. Из черновика C11, §5.1.2.4p7:

All modifications to a particular atomic object M occur in some particular total order, called the modification order of M.

Благодаря этому определению модификаций M возможно, что общий порядок, наблюдаемый каким-либо другим потоком, будет A / B, но B / A также разрешен. Это действительно привело бы к тому, что внешний наблюдатель заметил бы переход значения между -1 и 0 (при условии, что атомный тип со знаком).

Чтобы справиться с этим, стандарт определяет операции синхронизации (из параграфа 5 того же раздела):

A synchronization operation on one or more memory locations is either an acquire operation, a release operation, both an acquire and release operation, or a consume operation.

Позже есть несколько утомительных для чтения определений компоновки этих операций, чтобы ввести зависимости, которые в конечном итоге приводят к упорядочиванию «происходит до». Я их опущу; §5.1.2.4p14-22 описывает наблюдаемость побочных эффектов для некоторого объекта и то, как зависимости влияют на это; В §7.17.3 описывается API для управления этими зависимостями.

Не обсуждая эти разделы, можно надеяться, что достаточно сказать, что они позволяют наблюдателю видеть описанный «противоположный порядок». Вы можете попасть в эту ситуацию, если используете atomic_fetch_add_explicit с аргументом memory_order_relaxed, а ваша нагрузка реализована как atomic_load_explicit с такими же ослабленными требованиями к упорядочиванию памяти. В этой ситуации связь «происходит до» не определена, и системе разрешается разрешить потоку C наблюдать за изменениями в любом порядке.

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

Если бы вы реализовали это исключительно с atomic_fetch_add, atomic_fetch_sub и atomic_load (как вы, вероятно, сделали бы), все будет в порядке; стандарт в §7.17.1p5 гласит:

The functions not ending in _explicit have the same semantics as the corresponding _explicit function with memory_order_seq_cst for the memory_order argument.

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

При этом все сказано: если вы можете использовать C11, просто используйте ++, -- и =, и все будет в порядке. Согласно §6.5.16.2p3, операции += и -= с атомарными типами определены так, как если бы они использовали хранилище с memory_order_seq_cst. Согласно §6.5.3p2 операторы ++ и -- аналогичны эквивалентным выражениям x+=1 и x-=1. Простое присвоение (§6.5.16.2) указывает, что LHS или RHS могут быть атомарными типами, но не определяет порядок памяти. Йенс Густедт говорит, что операции с объектами, отвечающими требованиям _Atomic, гарантированно имеют последовательную согласованность. Я могу догадаться об этом только по сноске 113, а сноски не являются нормативными. Но я не думаю, что это имеет значение: если все записи согласованы, при любом чтении должно соблюдаться действительное предыдущее состояние из этого общего порядка, которое никогда не содержит -1.

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