Spec-Zone.ru › GCC 10

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

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

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

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

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

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

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

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

Встроенная функция: 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 байт всегда генерируют инструкции атомарного доступа без блокировки для целевой архитектуры. Если встроенная функция не известна как без блокировки, вызывается внешняя функция runtime под названием __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-10.5.0/gcc/_005f_005fatomic-Builtins.html

Spec-Zone.ru

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