Что означает каждая память?

Я прочитал главу, и мне это не понравилось. Я все еще не понимаю, каковы различия между каждым порядком памяти. Это мои текущие предположения, которые я понял после прочтения гораздо более простых http://en.cppreference.com/w/cpp/atomic/memory_order

Ниже указано неверно, поэтому не пытайтесь учиться на нем

  • memory_order_relaxed: не синхронизируется, но не игнорируется, когда заказ выполняется из другого режима в другой атомной var
  • memory_order_consume: Синхронизация чтения этой атомной переменной, но она не синхронизирует расслабленные вары, написанные до этого. Однако, если поток использует var X при изменении Y (и освобождает его). Другие потоки, потребляющие Y, также увидят X? Я не знаю, означает ли это, что эта нить выталкивает изменения x (и, очевидно, y)
  • memory_order_acquire: Синхронизация чтения этой атомной переменной И гарантирует, что расслабленные вары, написанные до этого, также синхронизируются. (означает ли это, что все атомные переменные во всех потоках синхронизируются?)
  • memory_order_release: помещает атомный магазин в другие потоки (но только если они читают var с потреблением/приобретением)
  • memory_order_acq_rel: для операций чтения/записи. Получает ли приобретение, поэтому вы не изменяете старое значение и не выпускаете изменения.
  • memory_order_seq_cst: то же самое, что и получение релиза, за исключением того, что оно заставляет обновления отображаться в других потоках (если a сохранить с расслабленным в другом потоке.Я храню b с seq_cst. 3-й поток, читающий a с relax увидит изменения вместе с b и любой другой атомной переменной?).

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

30
10 сент. '12 в 9:39
источник поделиться
2 ответов

GCC Wiki дает очень подробное и понятное объяснение с примерами кода.

(отредактирован фрагмент и добавлено выделение)

ВАЖНО:

После повторного чтения приведенной ниже цитаты, скопированной из Wiki GCC, в процессе добавления моей собственной формулировки к ответу, я заметил, что цитата на самом деле неверна. Они приобретают и потребляют точно неправильный путь. Операция "освобождение-освобождение" обеспечивает только гарантию заказа на зависимые данные, тогда как операция освобождения-освобождения обеспечивает эту гарантию независимо от того, зависят ли данные от атомного значения или нет.

Первая модель является "последовательной последовательностью". Это режим по умолчанию, который используется, когда ни один не указан, и является наиболее ограничительным. Он также может быть явно указан через memory_order_seq_cst. Он обеспечивает те же ограничения и ограничения для движущихся нагрузок вокруг того, что последовательные программисты по своей сути знакомы, за исключением того, что они применяются по потокам.
[...]
С практической точки зрения это сводится ко всем атомным операциям, действующим в качестве барьеров оптимизации. Это нормально, чтобы переупорядочить вещи между атомными операциями, но не через операцию. Неполадки на местном уровне также не затрагиваются, поскольку нет видимости для других потоков. [...] Этот режим также обеспечивает согласованность потоков all.

противоположный подход memory_order_relaxed. Эта модель позволяет значительно сократить синхронизацию, удалив ограничения, которые происходят до этого. Эти типы атомных операций могут также иметь различные оптимизации, выполняемые на них, такие как удаление мертвых хранилищ и их распространение. [...] Без каких-либо событий - до ребер, нить не может рассчитывать на конкретный заказ из другого потока. Расслабленный режим наиболее часто используется, когда программист просто хочет, чтобы переменная была атомной по своей природе, а не использовала ее для синхронизации потоков для других данных общей памяти.

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

memory_order_consume является еще одним тонким усовершенствованием в модели памяти освобождения/приобретения, которая немного ослабляет требования, удаляя это, прежде чем заказывать на не зависимых общих переменных.
[...]
Реальное различие сводится к тому, сколько оборудования оборудовано для синхронизации, чтобы синхронизировать. Так как операция потребления может выполняться быстрее, кто-то, кто знает, что они делают, может использовать ее для критически важных приложений.

Здесь следует моя собственная попытка более мирского объяснения:

Другой подход, чтобы посмотреть на это, - это посмотреть на проблему с точки зрения переупорядочения чтений и записей, как атомных, так и обычных:

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

Теперь расслабленный - это тот, что голый минимум. Он ничего не делает и не дает никаких других гарантий. Это самая дешевая операция. Для операций без чтения-изменения-записи на сильно упорядоченных архитектурах процессоров (например, x86/amd64) это сводится к обычным обычным ходом.

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

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

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

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

В настоящее время не рекомендуется использовать упорядочение потребления во время пересмотра спецификации.

31
30 дек. '12 в 18:12
источник

Связанные вопросы


Похожие вопросы

Это довольно сложный вопрос. Попытайтесь читать http://en.cppreference.com/w/cpp/atomic/memory_order несколько раз, попробуйте прочитать другие ресурсы и т.д.

Здесь приведено упрощенное описание:

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

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

Итак, единственной проблемой, с которой мы сталкиваемся, является переупорядочение доступа к памяти. Переменная memory_order указывает, какие типы компиляторов переупорядочения должны быть запрещены.

relaxed - никаких ограничений.

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

acquire - никакие нагрузки не могут быть переупорядочены по адресу. атомная нагрузка. То есть если они находятся после атомной нагрузки в исходном коде, они будут происходить и после атомной нагрузки.

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

acq_rel - acquire и release в сочетании.

seq_cst - сложнее понять, почему этот заказ требуется. В принципе, все остальные упорядочения гарантируют, что определенные запрещенные переупорядочения не будут выполняться только для потоков, которые потребляют/выпускают одну и ту же атомную переменную. Доступ к памяти может по-прежнему распространяться на другие потоки в любом порядке. Это упорядочение гарантирует, что этого не произойдет (таким образом, последовательная согласованность). Для случая, когда это необходимо, см. Пример в конце связанной страницы.

18
10 сент. '12 в 15:01
источник

Посмотрите другие вопросы по меткам или Задайте вопрос