Spec-Zone.ru › GCC 12

6.55 Встроенные функции для операций с атомарными данными с учётом модели памяти

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

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

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

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

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

Встроенная функция: 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

Объект, на который указывает первый аргумент, должен быть целочисленного или указатель-типа. Он не должен быть булевым типом. Все порядки памяти допустимы.

Встроенная функция: тип __atomic_fetch_add (тип *указатель, тип значение, int порядок_памяти)
Встроенная функция: тип __atomic_fetch_sub (тип *указатель, тип значение, int порядок_памяти)
Встроенная функция: тип __atomic_fetch_and (тип *указатель, тип значение, int порядок_памяти)
Встроенная функция: тип __atomic_fetch_xor (тип *указатель, тип значение, int порядок_памяти)
Встроенная функция: тип __atomic_fetch_or (тип *указатель, тип значение, int порядок_памяти)
Встроенная функция: тип __atomic_fetch_nand (тип *указатель, тип значение, int порядок_памяти)

Эти встроенные функции выполняют операцию, соответствующую их названию, и возвращают значение, которое ранее находилось в *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 *указатель, int порядок_памяти)

Эта встроенная функция выполняет атомную операцию «проверка и установка» для байта по адресу *ptr. Байт устанавливается в некоторое определенное реализацией ненулевое значение («установлено»), а возвращаемое значение равно true тогда и только тогда, когда предыдущее содержимое было «установлено». Ее следует использовать только для операндов типа bool или char. Для других типов может быть установлена только часть значения.

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

Встроенная функция: void __atomic_clear (bool *указатель, int порядок_памяти)

Эта встроенная функция выполняет атомную операцию сброса для *ptr. После выполнения операции, *ptr содержит 0. Ее следует использовать только для операндов типа bool или char, и в сочетании с __atomic_test_and_set. Для других типов она может сбрасывать только частично. Если тип не bool, предпочтительнее использовать __atomic_store.

Допустимые варианты порядка памяти — __ATOMIC_RELAXED, __ATOMIC_SEQ_CST, и __ATOMIC_RELEASE.

Встроенная функция: void __atomic_thread_fence (int порядок_памяти)

Эта встроенная функция действует как барьер синхронизации между потоками на основе указанного порядка памяти.

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

Встроенная функция: void __atomic_signal_fence (int порядок_памяти)

Эта встроенная функция действует как барьер синхронизации между потоком и обработчиками сигналов в том же потоке.

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

Встроенная функция: bool __atomic_always_lock_free (size_t размер, void *указатель)

Эта встроенная функция возвращает true, если объекты размером размер байт всегда генерируют атомарные инструкции без блокировки для целевой архитектуры. размер должен быть константой времени компиляции, и результат также должен быть константой времени компиляции.

указатель — необязательный указатель на объект, который может быть использован для определения выравнивания. Значение 0 указывает, что должно использоваться стандартное выравнивание. Компилятор может проигнорировать этот параметр.

if (__atomic_always_lock_free (sizeof (long long), 0))
Встроенная функция: bool __atomic_is_lock_free (size_t размер, void *указатель)

Эта встроенная функция возвращает true, если объекты размером размер байт всегда генерируют атомарные инструкции без блокировки для целевой архитектуры. Если не известно, что встроенная функция является безблокировочной, вызывается процедура выполнения с именем __atomic_is_lock_free.

указатель — необязательный указатель на объект, который может быть использован для определения выравнивания. Значение 0 указывает, что должно использоваться стандартное выравнивание. Компилятор может проигнорировать этот параметр.

Далее: Встроенные функции для переполнения целых чисел, Предыдущее: Встроенные функции __sync, Наверх: Расширения языка C [Содержание][Индекс]

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/_005f_005fatomic-Builtins.html

Spec-Zone.ru

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