6.54 Встроенные функции __sync для атомарного доступа к памяти ¶
Следующие встроенные функции предназначены для совместимости с описанными в спецификации Intel Itanium Processor-specific Application Binary Interface, раздел 7.4. В связи с этим, они отклоняются от обычной практики 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, то запишите newval в*ptr.Версия «bool» возвращает
trueесли сравнение успешно и newval записано. Версия «val» возвращает содержимое*ptrдо операции. __sync_synchronize (...)-
Эта встроенная функция выдает полный барьер памяти.
type __sync_lock_test_and_set (type *ptr, type value, ...)-
Эта встроенная функция, как описано в Intel, не является традиционной операцией тестирования и установки, а скорее атомарной операцией обмена. Она записывает value в
*ptr, и возвращает предыдущее содержимое*ptr.Многие целевые платформы имеют только минимальную поддержку таких блокировок и не поддерживают полную операцию обмена. В этом случае целевая платформа может поддерживать здесь уменьшенную функциональность, при которой единственное допустимое значение для хранения — это немедленная константа 1. Точное значение, фактически сохранённое в
*ptr, зависит от реализации.Эта встроенная функция не является полной преградой, а скорее барьером приобретения. Это означает, что ссылки после операции не могут перемещаться к (или быть предположенными до) операции, но предыдущие операции сохранения памяти могут ещё не быть глобально видимыми, и предыдущие операции загрузки памяти ещё не могут быть удовлетворены.
void __sync_lock_release (type *ptr, ...)-
Эта встроенная функция освобождает блокировку, приобретённую с помощью
__sync_lock_test_and_set. Обычно это означает запись константы 0 в*ptr.Эта встроенная функция не является полной преградой, а скорее барьером выпуска. Это означает, что все предыдущие операции сохранения памяти глобально видны, и все предыдущие операции загрузки памяти выполнены, но последующие операции чтения памяти не препятствуют их предположению до барьера.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-10.5.0/gcc/_005f_005fsync-Builtins.html