Spec-Zone.ru › GCC 13

6.55 Встроенные функции для операций атомарного доступа, учитывающие модель памяти

Следующие встроенные функции приблизительно соответствуют требованиям модели памяти C++11. Все они идентифицируются префиксом «__atomic», и большинство из них перегружены для работы с несколькими типами.

Эти функции предназначены для замены устаревших встроенных функций «__sync». Основное различие заключается в том, что порядок памяти, который запрашивается, является параметром функций. Новый код всегда должен использовать встроенные функции «__atomic», а не «__sync».

Обратите внимание, что встроенные функции «__atomic» предполагают, что программы будут соответствовать модели памяти C++11. В частности, они предполагают, что программы свободны от гонок данных. Подробные требования см. в стандарте C++11.

Встроенные функции «__atomic» могут использоваться с любым целочисленным скалярным типом или указателем длиной 1, 2, 4 или 8 байт. 16-байтовые целочисленные типы также разрешены, если архитектура поддерживает «__int128» (см. 128-битные целые числа).

Четыре неарифметические функции (load, store, exchange и compare_exchange) также имеют общую версию. Эта общая версия работает с любым типом данных. Она использует встроенную функцию без блокировки, если размер конкретного типа данных позволяет это; в противном случае внешнее обращение разрешается во время выполнения. Это внешнее обращение имеет тот же формат с добавлением параметра «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.

Все варианты порядка памяти допустимы.

Встроенная функция: 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, за исключением того, что желаемое значение также является указателем.

END_OF_DOCUMENT_MARKER
Встроенная функция: 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-13.3.0/gcc/_005f_005fatomic-Builtins.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API