LLVM - Atomi c Заказ неупорядочен - PullRequest
1 голос
/ 13 февраля 2020

Я работаю над библиотекой, которая в значительной степени опирается на побитовые операции, где самые важные работают с разделяемой памятью. Я также взглянул на документацию по заказу Atom c от LLVM и заметил неупорядоченный , который кажется даже слабее, чем ослабленный порядок памяти в C / C ++. У меня есть несколько вопросов об этом:

  • В чем различия между неупорядоченным и расслабленным ?
  • Скажите, что у меня есть атомы c bool, безопасно ли изменять его через неупорядоченный загрузить / сохранить ?
  • Скажите, у меня есть атомная c битовая маска, безопасно ли изменять его через неупорядоченный загрузка / хранение ?
  • Безопасно ли его изменять с помощью неупорядоченный fetch_and / или / xor ?
  • Безопасно ли изменять его с помощью неупорядоченный swap ?
  • Безопасно ли изменять его с помощью неупорядоченный Compare_and_swap ?

1 Ответ

0 голосов
/ 16 февраля 2020

Короткий ответ: какой бы ни была ваша проблема, неупорядоченная вряд ли будет решением проблемы!

Более длинный ответ ...


... Справочное руководство по языку LLVM гласит:

неупорядочено

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

«Значение не может быть прочитано, если какая-то операция его не записала». это весело ! Это означает, что «спекулятивные» записи не допускаются. Допустим, у вас есть if (y == 99) x = 0 ; else x = y+1 ;: оптимизатор может превратить это в x = y+1 ; if (y == 99) x = 0 ;, где первая запись x является «спекулятивной». (Я не говорю, что это разумная или обычная оптимизация. Дело в том, что преобразования, которые совершенно нормальны с точки зрения отдельного потока, не подходят для атомарных процессов.) Стандарты C / C ++ имеют то же ограничение: нет «out» допустимы значения "из воздуха".

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

Кажется монотонным c является локальным именем для C / C ++ memory_order_relaxed и описывается:

monotoni c

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

В отличие от неупорядоченного , с monotoni c все потоки будут видеть записи по данному адресу в том же порядке. Это означает, что если поток «a» записывает «1» в заданное место, а затем поток «b» пишет «2», то после этого потоки «c» и «d» должны оба прочитать «2». (Отсюда и название.)

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

Это расслабленный бит.

Операция чтения в атоме c операция чтения-изменения-записи (cmpxchg и atomicrmw) читает значение в порядке изменения непосредственно перед записываемым значением.

То же, что C / C ++: чтение-изменение-запись не может быть прервано другой записью .

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

Это однообразное c, ребята.

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

Так что ... может быть некоторая задержка между записью и чтением, но эта задержка конечна (но, я полагаю, не может быть одинаковой для всех потоков). «В конце концов» интересно. Стандарт C11 гласит: «Реализации должны сделать хранилища atomi c видимыми для загрузок atomi c в течение разумного промежутка времени», что аналогично, но с более позитивным вращением: -)

Это соответствует C ++ 0x / C1x memory_order_relaxed.

Итак, вы go.


Вы спросили:

  • Скажем, у меня атоми c bool, безопасно ли изменять его через неупорядоченную загрузку / хранение?
  • Скажем, у меня есть атомарная c битовая маска, безопасно ли изменять ее через неупорядоченную загрузку / хранилище?

Это скорее зависит от того, что вы подразумеваете под safe :-( С любым атомом c загрузкой 'x', за которой следует атоми c хранилище 'x', у вас есть без понятия сколько других магазинов до 'x с момента загрузки. Но добавленная радость неупорядоченного заключается в том, что он не гарантирует, что все потоки будут видеть все записи в 'x' в том же порядке!

Ваш другие вопросы спорны, потому что вы не можете иметь неупорядоченные операции чтения-изменения-записи.

На практике ваш x86_64 гарантирует, что все записи видны всем потокам в одном и том же порядке - - так что все операции atomi c выполняются как минимум monotoni c / memory_order_relaxed - нет префиксов LOCK и никаких инструкций xFENCE не требуется, просто MOV для памяти будет сделать трюк. На самом деле, лучше, чем это, простой MOV в / из памяти дает memory_order_release / memory_order_acquire. * 113 1 *


FWIW: вы упоминаете побитовые операции. Я думаю, очевидно, что чтение / запись нескольких битов будет включать чтение / запись некоторого количества других битов в качестве побочного эффекта. Что добавляет веселья.

Я предполагаю, что как минимум вам нужно будет выполнять операции чтения-изменения-записи. Опять же, на x86_64 это сводится к инструкции с префиксом LOCK, которая обойдется в 10 секунд - сколько из них зависит от процессора и степени конкуренции. Теперь блокировка и разблокировка mutex будут включать редактирование LOCK, поэтому обычно стоит заменить mutex_lock / ... выполнить чтение и запись ... / mutex_unlock на атомом c read-modify- запись (и) действительно только в том случае, если это только одна операция чтения-изменения-записи.

Недостаток мьютекса, конечно, в том, что поток может быть "заменен", пока он содержит мьютекс: - (

Для спин-блокировки (на x86_64) требуется LOCK для получения, но не для отпускания ... но эффект "вытаскивания" при удерживании спин-блокировки еще хуже: - (

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