6.57 Встроенные функции для операций с атомарными данными, учитывающими модель памяти
Следующие встроенные функции приблизительно соответствуют требованиям модели памяти C++11. Все они идентифицируются префиксом ‘__atomic’ и, в большинстве случаев, перегружены для работы с несколькими типами.
Эти функции предназначены для замены устаревших встроенных функций ‘__sync’. Основное различие заключается в том, что порядок памяти, который требуется, является параметром функций. Новый код всегда должен использовать встроенные функции ‘__atomic’ вместо встроенных функций ‘__sync’.
Обратите внимание, что встроенные функции ‘__atomic’ предполагают, что программы будут соответствовать модели памяти C++11. В частности, они предполагают, что программы свободны от гонок данных. Подробные требования см. в стандарте C++11.
Встроенные функции ‘__atomic’ могут использоваться с любым целочисленным скалярным типом или указателем, длина которого составляет 1, 2, 4 или 8 байта. 16-байтовые целочисленные типы также разрешены, если архитектура поддерживает ‘__int128’ (см. 128-битные целые числа).
Четыре неарифметические функции (загрузка, сохранение, обмен и сравнение_с_обменом) также имеют общую версию. Эта общая версия работает с любым типом данных. Она использует встроенную функцию без блокировки, если размер конкретного типа данных позволяет это; в противном случае внешний вызов остается для разрешения во время выполнения. Этот внешний вызов имеет тот же формат, с добавлением параметра ‘size_t’, вставленного в качестве первого параметра, указывающего размер объекта, на который указывает указатель. Все объекты должны быть одинакового размера.
Существует 6 различных порядков памяти, которые можно указать. Они соответствуют порядкам памяти C++11 с теми же именами, см. стандарт C++11 или вики GCC по атомарной синхронизации для подробных определений. Отдельные целевые платформы могут также поддерживать дополнительные порядки памяти для использования на определённых архитектурах. Подробности см. в документации по целевой платформе.
Атомарная операция может ограничивать перемещение кода и быть отображена на аппаратные инструкции для синхронизации между потоками (например, барьер). В какой степени это происходит, регулируется порядками памяти, которые перечислены здесь приблизительно в порядке возрастания силы. Описание каждого порядка памяти предназначено только для приблизительного иллюстрации эффектов и не является спецификацией; см. модель памяти C++11 для точной семантики.
__ATOMIC_RELAXEDНе подразумевает ограничений порядка между потоками.
__ATOMIC_CONSUMEВ настоящее время это реализуется с использованием более строгого
__ATOMIC_ACQUIREпорядка памяти из-за недостатка семантики C++11 дляmemory_order_consume.__ATOMIC_ACQUIREСоздает ограничение «происходит-раньше» между потоками от оператора сохранения (или более сильного) семантического типа к этой оператору загрузки типа acquire. Может предотвратить поднятие кода до операции.
__ATOMIC_RELEASEСоздает ограничение «происходит-раньше» между потоками для операций загрузки типа acquire (или более сильного) семантики, которые считывают из этого сохранения типа release. Может предотвратить опускание кода после операции.
__ATOMIC_ACQ_RELОбъединяет эффекты как
__ATOMIC_ACQUIRE, так и__ATOMIC_RELEASE.__ATOMIC_SEQ_CSTВызывает полное упорядочение со всеми остальными
__ATOMIC_SEQ_CSTоперациями.
Обратите внимание, что в модели памяти C++11, барьеры (например, ‘__atomic_thread_fence’) вступают в силу в сочетании с другими атомарными операциями над конкретными областями памяти (например, атомарными загрузками); операции над конкретными областями памяти не обязательно влияют на другие операции таким же образом.
Архитектурам целевых платформ рекомендуется предоставлять свои собственные шаблоны для каждой из атомарных встроенных функций. Если целевая платформа не предоставлена, используются исходные атомарные встроенные функции ‘__sync’ без учета модели памяти, а также все необходимые синхронизирующие барьеры вокруг неё для достижения правильного поведения. Выполнение в этом случае подчиняется тем же ограничениям, что и встроенные функции.
Если нет шаблона или механизма для предоставления последовательности инструкций без блокировки, вызов делается во внешнюю функцию с теми же параметрами для разрешения во время выполнения.
При реализации шаблонов для этих встроенных функций параметр порядка памяти можно игнорировать, до тех пор, пока шаблон реализует наиболее ограничительный __ATOMIC_SEQ_CST порядок памяти. Любой другой порядок памяти выполняется корректно с этим порядком памяти, но он может выполняться не так эффективно, как с более подходящей реализацией расслабленных требований.
Обратите внимание, что стандарт C++11 допускает определение параметра порядка памяти во время выполнения, а не во время компиляции. Эти встроенные функции отображают любое значение во время выполнения в __ATOMIC_SEQ_CST вместо вызова функции времени выполнения или вставки оператора switch. Это соответствует стандарту, безопасно и является наиболее простым подходом на данный момент.
Параметр порядка памяти — целое число со знаком, но только младшие 16 биты зарезервированы для порядка памяти. Остальная часть целого числа со знаком зарезервирована для использования целевой платформы и должна быть равна 0. Используйте предварительно определённые атомарные значения для обеспечения правильного использования.
-
Встроенная функция:
type__atomic_load_n(type *ptr, int memorder) -
Эта встроенная функция реализует атомарную операцию загрузки. Она возвращает содержимое
*ptr.Допустимые варианты порядка памяти —
__ATOMIC_RELAXED,__ATOMIC_SEQ_CST,__ATOMIC_ACQUIRE, и__ATOMIC_CONSUME.
-
Встроенная функция:
void__atomic_load(type *ptr, type *ret, int memorder) -
Это общая версия атомарной загрузки. Она возвращает содержимое
*ptrв*ret.
-
Встроенная функция:
void__atomic_store_n(type *ptr, type val, int memorder) -
Эта встроенная функция реализует атомарную операцию сохранения. Она записывает
valв*ptr.Допустимые варианты порядка памяти —
__ATOMIC_RELAXED,__ATOMIC_SEQ_CST, и__ATOMIC_RELEASE.
-
Встроенная функция:
void__atomic_store(type *ptr, type *val, int memorder) -
Это общая версия атомарного сохранения. Она сохраняет значение
*valв*ptr.
-
Встроенная функция:
type__atomic_exchange_n(type *ptr, type val, int memorder) -
Эта встроенная функция реализует атомарную операцию обмена. Она записывает val в
*ptr, и возвращает предыдущее содержимое*ptr.Все варианты порядка памяти допустимы.
-
Встроенная функция:
void__atomic_exchange(type *ptr, type *val, type *ret, int memorder) -
Это общая версия атомарного обмена. Она сохраняет содержимое
*valв*ptr. Исходное значение*ptrкопируется в*ret.
-
Встроенная функция:
bool__atomic_compare_exchange_n(type *ptr, type *expected, type desired, bool weak, int success_memorder, int failure_memorder) -
Эта встроенная функция реализует атомарную операцию сравнения и обмена. Она сравнивает содержимое
*ptrс содержимым*expected. Если они равны, операция выполняется как чтение-модификация-запись, которая записывает desired в*ptr. Если они не равны, операция выполняется как чтение, и текущее содержимое*ptrзаписывается в*expected. weak равноtrueдля слабого сравнения_с_обменом, которое может случайным образом терпит неудачу, иfalseдля сильного варианта, который никогда не терпит случайной неудачи. Многие целевые платформы предлагают только сильный вариант и игнорируют параметр. В случае сомнения используйте сильный вариант.Если desired записывается в
*ptr, тоtrueвозвращается, и память изменяется в соответствии с порядком памяти, указанным success_memorder. Нет ограничений на то, какой порядок памяти может здесь использоваться.В противном случае,
falseвозвращается, и память изменяется в соответствии с failure_memorder. Этот порядок памяти не может быть__ATOMIC_RELEASEни__ATOMIC_ACQ_REL. Он также не может быть сильнее, чем тот, который указан в success_memorder.
-
Встроенная функция:
bool__atomic_compare_exchange(type *ptr, type *expected, type *desired, bool weak, int success_memorder, int failure_memorder) -
Эта встроенная функция реализует общую версию
__atomic_compare_exchange. Функция практически идентична__atomic_compare_exchange_n, за исключением того, что желаемое значение также является указателем.
-
Встроенная функция:
type__atomic_add_fetch(type *ptr, type val, int memorder) -
Встроенная функция:
type__atomic_sub_fetch(type *ptr, type val, int memorder) -
Встроенная функция:
type__atomic_and_fetch(type *ptr, type val, int memorder) -
Встроенная функция:
type__atomic_xor_fetch(type *ptr, type val, int memorder) -
Встроенная функция:
type__atomic_or_fetch(type *ptr, type val, int memorder) -
Встроенная функция:
type__atomic_nand_fetch(type *ptr, type val, int memorder) -
Эти встроенные функции выполняют операцию, указанную в их имени, и возвращают результат операции. Операции с аргументами-указателями выполняются так, как если бы операнды были типа
uintptr_t. То есть, они не масштабируются с учетом размера типа, на который указывает указатель.{ *ptr op= val; return *ptr; } { *ptr = ~(*ptr & val); return *ptr; } // nandОбъект, на который указывает первый аргумент, должен быть целого или указатель типа. Он не должен быть булевым типом. Все порядки памяти допустимы.
-
Встроенная функция:
type__atomic_fetch_add(type *ptr, type val, int memorder) -
Встроенная функция:
type__atomic_fetch_sub(type *ptr, type val, int memorder) -
Встроенная функция:
type__atomic_fetch_and(type *ptr, type val, int memorder) -
Встроенная функция:
type__atomic_fetch_xor(type *ptr, type val, int memorder) -
Встроенная функция:
type__atomic_fetch_or(type *ptr, type val, int memorder) -
Встроенная функция:
type__atomic_fetch_nand(type *ptr, type val, int memorder) -
Эти встроенные функции выполняют операцию, указанную в их имени, и возвращают значение, которое ранее было в
*ptr. Операции с аргументами-указателями выполняются так, как если бы операнды были типаuintptr_t. То есть, они не масштабируются с учетом размера типа, на который указывает указатель.{ tmp = *ptr; *ptr op= val; return tmp; } { tmp = *ptr; *ptr = ~(*ptr & val); return tmp; } // nandПрименяются те же ограничения к аргументам, что и для соответствующих встроенных функций
__atomic_op_fetch. Все порядки памяти допустимы.
-
Встроенная функция:
bool__atomic_test_and_set(void *ptr, int memorder) -
Эта встроенная функция выполняет атомную операцию проверки и установки бита в байте по адресу
*ptr. Байт устанавливается в некоторое реализационно-зависимое ненулевое значение ("установлено"), а возвращаемое значение равноtrueтолько в том случае, если предыдущее содержимое было "установлено". Она должна использоваться только для операндов типаboolилиchar. Для других типов может быть установлена только часть значения.Все порядки памяти допустимы.
-
Встроенная функция:
void__atomic_clear(bool *ptr, int memorder) -
Эта встроенная функция выполняет атомную операцию очистки
*ptr. После операции*ptrсодержит 0. Она должна использоваться только для операндов типаboolилиchar, и в сочетании с__atomic_test_and_set. Для других типов может быть очищена только часть значения. Если тип неbool, предпочтительнее использовать__atomic_store.Допустимые варианты порядка памяти —
__ATOMIC_RELAXED,__ATOMIC_SEQ_CST, и__ATOMIC_RELEASE.
-
Встроенная функция:
void__atomic_thread_fence(int memorder) -
Эта встроенная функция выполняет барьер синхронизации между потоками, основанный на указанном порядке памяти.
Все порядки памяти допустимы.
-
Встроенная функция:
void__atomic_signal_fence(int memorder) -
Эта встроенная функция выполняет барьер синхронизации между потоком и обработчиками сигналов в том же потоке.
Все порядки памяти допустимы.
-
Встроенная функция:
bool__atomic_always_lock_free(size_t size, void *ptr) -
Эта встроенная функция возвращает
trueесли объекты размером size байт всегда генерируют блокировки-свободные атомные инструкции для целевой архитектуры. size должно быть константой времени компиляции, и результат тоже должен быть константой времени компиляции.ptr — необязательный указатель на объект, который может использоваться для определения выравнивания. Значение 0 указывает, что должно использоваться типичное выравнивание. Компилятор может также проигнорировать этот параметр.
if (__atomic_always_lock_free (sizeof (long long), 0))
-
Встроенная функция:
bool__atomic_is_lock_free(size_t size, void *ptr) -
Эта встроенная функция возвращает
trueесли объекты размером size байт всегда генерируют блокировки-свободные атомные инструкции для целевой архитектуры. Если встроенная функция не известна как блокировки-свободная, вызов осуществляется к функции времени выполнения, названной__atomic_is_lock_free.ptr — необязательный указатель на объект, который может использоваться для определения выравнивания. Значение 0 указывает, что должно использоваться типичное выравнивание. Компилятор может также проигнорировать этот параметр.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-14.2.0/gcc/_005f_005fatomic-Builtins.html