6.55 Встроенные функции для операций с атомной памятью с учётом модели памяти ¶
Следующие встроенные функции приблизительно соответствуют требованиям модели памяти 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Создаёт ограничение «происходит-до» между потоками от операции сохранения (или более сильной) семантики до операции загрузки с модификатором «приобретение». Может предотвращать поднятие кода до операции.
__ATOMIC_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.Допустимые варианты порядка памяти —
__ATOMIC_RELAXED,__ATOMIC_SEQ_CST,__ATOMIC_ACQUIRE,__ATOMIC_RELEASE, и__ATOMIC_ACQ_REL.
-
Встроенная функция:
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 байт всегда генерируют инструкции атомарного доступа без блокировки для целевой архитектуры. Если встроенная функция не известна как без блокировки, вызывается внешняя функция runtime под названием__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-10.5.0/gcc/_005f_005fatomic-Builtins.html