Spec-Zone.ru › C

Атомарные типы

Синтаксис

_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 is a pointer to an atomic const int
const atomic_int* p2;   // same
const _Atomic(int)* p3; // same

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

Пояснение

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

У каждого атомарного объекта есть собственный порядок модификаций — полный порядок модификаций, выполненных для этого объекта. Если с точки зрения некоторого потока модификация A некоторого атомарного M происходит раньше модификации 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.

Некоторые атомарные операции также являются операциями синхронизации; они могут обладать дополнительной семантикой освобождения, захвата или последовательной согласованности. См. memory_order.

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

Атомарные свойства имеют смысл только для выражений lvalue. Преобразование lvalue в 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++ для atomic

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/c/language/atomic

Spec-Zone.ru

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