6.55 Встроенные функции для атомных операций с учетом модели памяти
Следующие встроенные функции примерно соответствуют требованиям модели памяти C++11. Все они идентифицируются префиксом ‘__atomic’ и большинство перегружены для работы с несколькими типами.
Эти функции предназначены для замены устаревших встроенных функций ‘__sync’. Основное отличие заключается в том, что порядок памяти, который запрашивается, является параметром функций. Новый код всегда должен использовать встроенные функции ‘__atomic’ вместо встроенных функций ‘__sync’.
Обратите внимание, что встроенные функции ‘__atomic’ предполагают, что программы будут соответствовать модели памяти C++11. В частности, они предполагают, что программы не содержат гонок данных. См. стандарт C++11 для подробных требований.
Встроенные функции ‘__atomic’ могут использоваться с любым целочисленным скалярным или указателем типа длиной 1, 2, 4 или 8 байт. 16-байтовые целочисленные типы также разрешены, если ‘__int128’ (см. __int128) поддерживается архитектурой.
Четыре функции, не являющиеся арифметическими (загрузка, сохранение, обмен и сравнение_обмен), также имеют общую версию. Эта общая версия работает с любым типом данных. Она использует встроенную функцию без блокировки, если размер конкретного типа данных позволяет это; в противном случае внешний вызов остается для решения во время выполнения. Этот внешний вызов имеет тот же формат с добавлением параметра ‘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.Допустимые варианты порядка памяти —
__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; } { *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 порядок_памяти)
-
Эта встроенная функция выполняет атомную операцию test-and-set для байта по адресу
*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-9.5.0/gcc/_005f_005fatomic-Builtins.html