Spec-Zone.ru › C

Атомные типы

Синтаксис

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

Заголовок <stdatomic.h> определяет 37 псевдонимов типов, от 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.

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

Гарантируется четыре согласованности для всех атомных операций:

  • Согласованность запись-запись: Если операция A, изменяющая атомный объект M, предшествует операции B, изменяющей M, то A появляется раньше B в порядке модификаций M.
  • Согласованность чтение-чтение: Если вычисление значения A атомного объекта M происходит до вычисления значения B объекта M, и A берёт своё значение из побочного эффекта X на M, то вычисленное значение B — это либо значение, сохранённое X, либо значение, сохранённое побочным эффектом Y на M, где Y появляется позже X в порядке модификаций M.
  • Согласованность чтение-запись: Если вычисление значения A атомного объекта M предшествует операции B на M, то A берёт своё значение из побочного эффекта X на M, где X появляется перед B в порядке модификаций M.
  • Согласованность запись-чтение: Если побочный эффект 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 <stdio.h>
#include <threads.h>
#include <stdatomic.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

Ссылки

  • Стандарт 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 для thread (Concurrency support library)
Документация по C++ для atomic

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

Spec-Zone.ru

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