7.9.2 Устаревшие встроенные функции __sync для атомарного доступа к памяти
Следующие встроенные функции предназначены для совместимости с функциями, описанными в разделе 7.4 документа «Application Binary Interface» для процессоров Intel Itanium. Поэтому они отличаются от обычной практики GCC: в их именах отсутствует префикс «__builtin_», и они перегружены, чтобы работать с несколькими типами.
В определении, приведённом в документации Intel, разрешено использовать только типы int, long, long long или их беззнаковые аналоги. GCC допускает любой скалярный тип размером 1, 2, 4 или 8 байт, кроме типа C _Bool или типа C++ bool. Операции с аргументами-указателями выполняются так, как если бы операнды имели тип uintptr_t. То есть они не масштабируются по размеру типа, на который указывает указатель.
Эти функции реализованы на основе встроенных функций «__atomic» (см. Встроенные функции атомарных операций с учётом модели памяти). Их не следует использовать в новом коде: вместо них следует использовать встроенные функции «__atomic».
Не все операции поддерживаются всеми целевыми процессорами. Если конкретную операцию невозможно реализовать на целевом процессоре, генерируется вызов внешней функции. Имя внешней функции совпадает с именем встроенной версии и дополнено суффиксом «_n», где n — размер типа данных.
В большинстве случаев эти встроенные функции считаются полным барьером. Это означает, что операнды памяти не перемещаются через операцию ни вперёд, ни назад. Кроме того, при необходимости выдаются инструкции, не позволяющие процессору спекулятивно загружать данные через операцию или ставить записи в очередь после операции.
В документации Intel для всех этих функций указано, что они принимают «необязательный список переменных, защищённых барьером памяти». Значение этого неясно: возможно, защищаются только перечисленные переменные, а возможно, это список дополнительных переменных, которые нужно защитить. GCC игнорирует этот список и считает его пустым. Пустой список GCC трактует как указание защитить все глобально доступные переменные.
-
Встроенная функция:
type__sync_fetch_and_add(type *ptr, type value, ...) -
Встроенная функция:
type__sync_fetch_and_sub(type *ptr, type value, ...) -
Встроенная функция:
type__sync_fetch_and_or(type *ptr, type value, ...) -
Встроенная функция:
type__sync_fetch_and_and(type *ptr, type value, ...) -
Встроенная функция:
type__sync_fetch_and_xor(type *ptr, type value, ...) -
Встроенная функция:
type__sync_fetch_and_nand(type *ptr, type value, ...) -
Эти встроенные функции выполняют операцию, указанную в имени, и возвращают значение, которое до этого находилось в памяти. То есть операции с целочисленными операндами имеют следующую семантику. Операции с аргументами-указателями выполняются так, как если бы операнды имели тип
uintptr_t. То есть они не масштабируются по размеру типа, на который указывает указатель.{ tmp = *ptr; *ptr op= value; return tmp; } { tmp = *ptr; *ptr = ~(tmp & value); return tmp; } // nandОбъект, на который указывает первый аргумент, должен иметь целочисленный тип или тип указателя. Он не должен иметь логический тип.
Примечание: в GCC 4.4 и более поздних версиях
__sync_fetch_and_nandреализована как*ptr = ~(tmp & value), а не как*ptr = ~tmp & value.
-
Встроенная функция:
type__sync_add_and_fetch(type *ptr, type value, ...) -
Встроенная функция:
type__sync_sub_and_fetch(type *ptr, type value, ...) -
Встроенная функция:
type__sync_or_and_fetch(type *ptr, type value, ...) -
Встроенная функция:
type__sync_and_and_fetch(type *ptr, type value, ...) -
Встроенная функция:
type__sync_xor_and_fetch(type *ptr, type value, ...) -
Встроенная функция:
type__sync_nand_and_fetch(type *ptr, type value, ...) -
Эти встроенные функции выполняют операцию, указанную в имени, и возвращают новое значение. То есть операции с целочисленными операндами имеют следующую семантику. Операции с операндами-указателями выполняются так, как если бы тип операнда был
uintptr_t.{ *ptr op= value; return *ptr; } { *ptr = ~(*ptr & value); return *ptr; } // nandК аргументам применяются те же ограничения, что и для соответствующих встроенных функций
__sync_op_and_fetch.Примечание: в GCC 4.4 и более поздних версиях
__sync_nand_and_fetchреализована как*ptr = ~(*ptr & value), а не как*ptr = ~*ptr & value.
-
Встроенная функция:
bool__sync_bool_compare_and_swap(type *ptr, type oldval, type newval, ...) -
Встроенная функция:
type__sync_val_compare_and_swap(type *ptr, type oldval, type newval, ...) -
Эти встроенные функции выполняют атомарную операцию сравнения и обмена. То есть, если текущее значение
*ptrравно oldval, в*ptrзаписывается newval.Версия «bool» возвращает
true, если сравнение успешно и записано значение newval. Версия «val» возвращает содержимое*ptrдо выполнения операции.
-
Встроенная функция:
void__sync_synchronize(...) Эта встроенная функция устанавливает полный барьер памяти.
-
Встроенная функция:
type__sync_lock_test_and_set(type *ptr, type value, ...) -
Эта встроенная функция, согласно описанию Intel, не является традиционной операцией «проверка и установка», а представляет собой атомарную операцию обмена. Она записывает value в
*ptrи возвращает предыдущее содержимое*ptr.Многие целевые платформы поддерживают такие блокировки лишь в минимальном объёме и не поддерживают полноценную операцию обмена. В этом случае целевая платформа может предоставлять здесь урезанную функциональность, при которой единственным допустимым для записи значением является непосредственная константа 1. Фактически записываемое в
*ptrзначение определяется реализацией.Эта встроенная функция не является полным барьером, а представляет собой барьер acquire. Это означает, что обращения, следующие за операцией, не могут перемещаться до неё (или выполняться спекулятивно до неё), однако предыдущие записи в память могут быть ещё не видны глобально, а предыдущие чтения из памяти могут быть ещё не завершены.
-
Встроенная функция:
void__sync_lock_release(type *ptr, ...) -
Эта встроенная функция освобождает блокировку, полученную с помощью
__sync_lock_test_and_set. Обычно это означает запись константы 0 в*ptr.Эта встроенная функция не является полным барьером, а представляет собой барьер release. Это означает, что все предыдущие записи в память видны глобально, а все предыдущие чтения из памяти завершены, однако последующие чтения из памяти не защищены от спекулятивного выполнения до барьера.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-15.3.0/gcc/_005f_005fsync-Builtins.html