6.53 Встроенные функции для операций с атомарными данными с учётом модели памяти
Следующие встроенные функции приблизительно соответствуют требованиям модели памяти 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 вместо вызова библиотечной функции во время выполнения или встраивания инструкции переключения. Это соответствует стандарту, безопасно и является самым простым подходом на данный момент.
Параметр порядка памяти — это целое число со знаком, но только младшие 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; }Объект, на который указывает первый аргумент, должен быть целочисленного или указательного типа. Он не должен быть булевым типом. Все порядки памяти допустимы.
- Встроенная функция: 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; }Те же ограничения на аргументы применяются, что и для соответствующих
__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 указывает, что следует использовать стандартное выравнивание. Компилятор также может игнорировать этот параметр.
Далее: Встроенные функции для переполнения целых чисел, Предыдущее: Встроенные функции __sync, Вверх: Расширения языка C [Содержание][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-7.5.0/gcc/_005f_005fatomic-Builtins.html