Namespaces
Variants

Atomic types

From cppreference.net

Содержание

Синтаксис

_Atomic ( type-name ) (1) (начиная с C11)
_Atomic type-name (2) (начиная с C11)
1) Используется как спецификатор типа; это обозначает новый атомарный тип
2) Используется как квалификатор типа; обозначает атомарную версию type-name . В этой роли может комбинироваться с const , volatile и restrict , однако, в отличие от других квалификаторов, атомарная версия type-name может иметь другой размер, выравнивание и представление объекта.
type-name - любой тип, кроме массива или функции. Для (1) , type-name также не может быть атомарным или cvr-квалифицированным

Заголовочный файл <stdatomic.h> определяет множество удобных псевдонимов типов , от atomic_bool до atomic_uintmax_t , которые упрощают использование этого ключевого слова со встроенными и библиотечными типами.

_Atomic const int* p1;  // p - указатель на атомарный const int
const atomic_int* p2;   // то же
const _Atomic(int)* p3; // то же

Если макроконстанта __STDC_NO_ATOMICS__ определена компилятором, ключевое слово _Atomic не предоставляется.

Объяснение

Объекты атомарных типов являются единственными объектами, свободными от гонок данных ; то есть они могут быть модифицированы двумя потоками одновременно или модифицированы одним потоком и прочитаны другим.

Каждый атомарный объект имеет свой собственный ассоциированный порядок модификаций , который представляет собой полный порядок модификаций, выполненных над этим объектом. Если, с точки зрения некоторого потока, модификация A некоторого атомарного M happens-before модификация B того же атомарного M , то в порядке модификаций M , A происходит перед B .

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

Существует четыре вида когерентности, которые гарантируются для всех атомарных операций:

  1. когерентность запись-запись : Если операция A , изменяющая атомарный объект M происходит-до операции B , изменяющей M , тогда A появляется раньше B в порядке модификации M .
  2. когерентность чтение-чтение : Если вычисление значения A атомарного объекта M происходит до вычисления значения B для M , и A получает своё значение из побочного эффекта X на M , тогда значение, вычисленное B , является либо значением, сохранённым X , либо значением, сохранённым побочным эффектом Y на M , где Y появляется позже X в порядке модификации M .
  3. когерентность чтение-запись : Если вычисление значения A атомарного объекта M происходит-до операции B на M , тогда A получает своё значение из побочного эффекта X на M , где X появляется до B в порядке модификации M .
  4. когерентность запись-чтение : Если побочный эффект X на атомарном объекте M происходит-до вычисления значения B для M , тогда вычисление B получает своё значение из X или из побочного эффекта Y , который появляется после X в порядке модификации M .

Некоторые атомарные операции также являются операциями синхронизации; они могут иметь дополнительную семантику освобождения (release), семантику захвата (acquire) или последовательно-согласованную семантику (sequentially-consistent). См. memory_order .

Встроенные операторы инкремента и декремента и составные присваивания являются атомарными операциями read-modify-write с полным последовательно согласованным упорядочением (как при использовании memory_order_seq_cst ). Если требуются менее строгие семантики синхронизации, вместо них могут использоваться функции стандартной библиотеки .

Атомарные свойства имеют смысл только для lvalue-выражений . Преобразование lvalue-to-rvalue (которое моделирует чтение памяти из атомарной ячейки в регистр процессора) снимает атомарность вместе с другими квалификаторами.

Примечания

Доступ к члену атомарной структуры/объединения является неопределенным поведением.

Тип библиотеки sig_atomic_t не обеспечивает межпоточную синхронизацию или упорядочивание памяти, только атомарность.

Типы volatile не обеспечивают межпоточную синхронизацию, порядок операций с памятью или атомарность.

Рекомендуется, чтобы реализации обеспечивали, чтобы представление _Atomic ( T ) в C совпадало с представлением std :: atomic < T > в C++ для любого возможного типа T . Механизмы, используемые для обеспечения атомарности и порядка памяти, должны быть совместимы.

Ключевые слова

_Atomic

Пример

#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>
atomic_int acnt;
int cnt;
int f(void* thr_data)
{
    for (int n = 0; n < 1000; ++n)
    {
        ++cnt;
        ++acnt;
        // for this example, relaxed memory order is sufficient, e.g.
        // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed);
    }
    return 0;
}
int main(void)
{
    thrd_t thr[10];
    for (int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for (int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);
    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

Возможный вывод:

The atomic counter is 10000
The non-atomic counter is 8644

Ссылки

  • Стандарт C23 (ISO/IEC 9899:2024):
  • 6.7.2.4 Спецификаторы атомарных типов (стр.: TBD)
  • 7.17 Атомарные операции <stdatomic.h> (стр.: TBD)
  • Стандарт C17 (ISO/IEC 9899:2018):
  • 6.7.2.4 Спецификаторы атомарных типов (стр: 87)
  • 7.17 Атомарные операции <stdatomic.h> (стр: 200-209)
  • Стандарт C11 (ISO/IEC 9899:2011):
  • 6.7.2.4 Спецификаторы атомарных типов (стр: 121)
  • 7.17 Атомарные операции <stdatomic.h> (стр: 273-286)

Смотрите также

Библиотека поддержки многопоточности
C++ documentation для atomic