std::atomic
| Определено в заголовочном файле <atomic>
|
||
template< class T > struct atomic; |
(1) | (начиная с C++11) |
template< class U > struct atomic<U*>; |
(2) | (начиная с C++11) |
| Определено в заголовочном файле <memory>
|
||
template< class U > struct atomic<std::shared_ptr<U>>; |
(3) | (начиная с C++20) |
template< class U > struct atomic<std::weak_ptr<U>>; |
(4) | (начиная с C++20) |
| Определено в заголовочном файле <stdatomic.h>
|
||
#define _Atomic(T) /* смотрите ниже */ |
(5) | (начиная с C++23) |
Каждое инстанцирование и полная специализация шаблона std::atomic определяет атомарный тип. Если один поток записывает в атомарный объект, а другой поток читает из него, поведение чётко определено (подробности о гонках данных смотрите в модели памяти.
Кроме того, доступ к атомарным объектам может установить межпотоковую синхронизацию и упорядочить доступ к неатомарной памяти, как указано в std::memory_order.
std::atomic нельзя ни копировать, ни перемещать.
|
Макрос совместимости Не указано, доступно ли какое-либо объявление в пространстве имён |
(начиная с C++23) |
Специализации
Основной шаблон
Основной шаблон std::atomic может быть создан с любым TriviallyCopyable типом T, соответствующим и CopyConstructible и CopyAssignable. Программа некорректна, если любое из следующих значений false:
std::is_trivially_copyable<T>::valuestd::is_copy_constructible<T>::valuestd::is_move_constructible<T>::valuestd::is_copy_assignable<T>::valuestd::is_move_assignable<T>::value
struct Counters { int a; int b; }; // определённый пользователем тип,
// допускающий тривиальное копирование
std::atomic<Counters> cnt; // специализация для определённого пользователем типа
std::atomic<bool> использует основной шаблон. Гарантируется, что это будет структура со стандартным выравниванием.
Частичные специализации
Стандартная библиотека предоставляет частичную специализацию шаблона std::atomic для следующих типов с дополнительными свойствами, которых нет у основного шаблона:
std::atomic<U*> для всех типов указателей. Эти специализации имеют стандартное выравнивание, тривиальные конструкторы по умолчанию, (до C++20) и тривиальные деструкторы. Помимо операций, предусмотренных для всех атомарных типов, эти специализации дополнительно поддерживают атомарные арифметические операции, соответствующие типам указателей, такие как fetch_add, fetch_sub.
|
3,4) Частичные специализации
std::atomic<std::shared_ptr<U>> и std::atomic<std::weak_ptr<U>> предусмотрены для std::shared_ptr и std::weak_ptr.Для подробной информации смотрите std::atomic<std::shared_ptr> и std::atomic<std::weak_ptr>. |
(начиная с C++20) |
Специализации для целочисленных типов
При создании экземпляра с одним из следующих целых типов std::atomic предоставляет дополнительные атомарные операции, соответствующие целочисленным типам, такие как fetch_add, fetch_sub, fetch_and, fetch_or, fetch_xor:
- Символьные типы
char,char8_t(начиная с C++20),char16_t,char32_tиwchar_t; - Стандартные целочисленные типы со знаком:
signed char,short,int,longиlong long; - Стандартные целочисленные типы без знака:
unsigned char,unsigned short,unsigned int,unsigned longиunsigned long long; - Любые дополнительные целочисленные типы, необходимые для typedef‘ов в заголовке <cstdint>.
- Символьные типы
Кроме того, получившаяся специализация std::atomic<Целочисленный тип> имеет стандартное выравнивание, тривиальный конструктор по умолчанию, (до C++20) и тривиальный деструктор. Знаковая целочисленная арифметика использует дополнение до двух; нет неопределённых результатов.
Специализации для типов с плавающей запятойПри создании экземпляра с одним из cv-неквалифицированных типов с плавающей запятой ( Кроме того, получившаяся специализация Никакие операции не приводят к неопределённому поведению, даже если результат не представляется в виде типа с плавающей запятой. Фактически среда с плавающей запятой может отличаться от среды с плавающей запятой вызывающего потока. |
(начиная с C++20) |
Псевдонимы типов
Для bool и всех перечисленных выше целочисленных типов предусмотрены следующие псевдонимы типов:
Псевдонимы для всех
| |
(C++11) |
std::atomic<bool> (определение типа) |
(C++11) |
std::atomic<char> (определение типа) |
(C++11) |
std::atomic<signed char> (определение типа) |
(C++11) |
std::atomic<unsigned char> (определение типа) |
(C++11) |
std::atomic<short> (определение типа) |
(C++11) |
std::atomic<unsigned short> (определение типа) |
(C++11) |
std::atomic<int> (определение типа) |
(C++11) |
std::atomic<unsigned int> (определение типа) |
(C++11) |
std::atomic<long> (определение типа) |
(C++11) |
std::atomic<unsigned long> (определение типа) |
(C++11) |
std::atomic<long long> (определение типа) |
(C++11) |
std::atomic<unsigned long long> (определение типа) |
(C++20) |
std::atomic<char8_t> (определение типа) |
(C++11) |
std::atomic<char16_t> (определение типа) |
(C++11) |
std::atomic<char32_t> (определение типа) |
(C++11) |
std::atomic<wchar_t> (определение типа) |
(C++11)(необязательно) |
std::atomic<std::int8_t> (определение типа) |
(C++11)(необязательно) |
std::atomic<std::uint8_t> (определение типа) |
(C++11)(необязательно) |
std::atomic<std::int16_t> (определение типа) |
(C++11)(необязательно) |
std::atomic<std::uint16_t> (определение типа) |
(C++11)(необязательно) |
std::atomic<std::int32_t> (определение типа) |
(C++11)(необязательно) |
std::atomic<std::uint32_t> (определение типа) |
(C++11)(необязательно) |
std::atomic<std::int64_t> (определение типа) |
(C++11)(необязательно) |
std::atomic<std::uint64_t> (определение типа) |
(C++11) |
std::atomic<std::int_least8_t> (определение типа) |
(C++11) |
std::atomic<std::uint_least8_t> (определение типа) |
(C++11) |
std::atomic<std::int_least16_t> (определение типа) |
(C++11) |
std::atomic<std::uint_least16_t> (определение типа) |
(C++11) |
std::atomic<std::int_least32_t> (определение типа) |
(C++11) |
std::atomic<std::uint_least32_t> (определение типа) |
(C++11) |
std::atomic<std::int_least64_t> (определение типа) |
(C++11) |
std::atomic<std::uint_least64_t> (определение типа) |
(C++11) |
std::atomic<std::int_fast8_t> (определение типа) |
(C++11) |
std::atomic<std::uint_fast8_t> (определение типа) |
(C++11) |
std::atomic<std::int_fast16_t> (определение типа) |
(C++11) |
std::atomic<std::uint_fast16_t> (определение типа) |
(C++11) |
std::atomic<std::int_fast32_t> (определение типа) |
(C++11) |
std::atomic<std::uint_fast32_t> (определение типа) |
(C++11) |
std::atomic<std::int_fast64_t> (определение типа) |
(C++11) |
std::atomic<std::uint_fast64_t> (определение типа) |
(C++11)(необязательно) |
std::atomic<std::intptr_t> (определение типа) |
(C++11)(необязательно) |
std::atomic<std::uintptr_t> (определение типа) |
(C++11) |
std::atomic<std::size_t> (определение типа) |
(C++11) |
std::atomic<std::ptrdiff_t> (определение типа) |
(C++11) |
std::atomic<std::intmax_t> (определение типа) |
(C++11) |
std::atomic<std::uintmax_t> (определение типа) |
Псевдонимы для специальных типов | |
(C++20) |
знаковый целочисленный атомарный тип, который свободен от блокировок и для которого ожидание/уведомление является наиболее эффективным (определение типа) |
(C++20) |
беззнаковый целочисленный атомарный тип, который свободен от блокировок и для которого ожидание/уведомление является наиболее эффективным (определение типа) |
Примечание: std::atomic_intN_t, std::atomic_uintN_t, std::atomic_intptr_t и std::atomic_uintptr_t определены тогда и только тогда, когда std::intN_t, std::uintN_t, std::intptr_t и std::uintptr_t определены соответственно.
|
|
(начиная с C++20) |
Типы-элементы
| Тип элемент | Определение |
value_type
|
T (независимо от того, специализирован или нет)
|
difference_type
|
value_type (только для специализаций atomic<Целочисленный тип> и atomic<Тип с плавающей запятой> (начиная с C++20))std::ptrdiff_t (только для специализаций std::atomic<U*>)
|
difference_type не определён в основном шаблоне std::atomic или в частичных специализациях для std::shared_ptr и std::weak_ptr.
Функции-элементы
| создаёт атомарный объект (public функция-элемент) | |
| сохраняет значение в атомарном объекте (public функция-элемент) | |
| проверяет, свободен ли атомарный объект от блокировки (public функция-элемент) | |
(C++11) |
атомарно заменяет значение атомарного объекта неатомарным аргументом (public функция-элемент) |
| атомарно получает значение атомарного объекта (public функция-элемент) | |
| загружает значение из атомарного объекта (public функция-элемент) | |
| атомарно заменяет значение атомарного объекта и получает ранее сохранённое значение (public функция-элемент) | |
| атомарно сравнивает значение атомарного объекта с неатомарным аргументом и выполняет атомарный обмен, если они равны, или атомарную загрузку, если нет (public функция-элемент) | |
| блокирует поток до тех пор, пока не получит уведомление и не изменится атомарное значение (public функция-элемент) | |
| уведомляет хотя бы один поток, ожидающий атомарный объект (public функция-элемент) | |
| уведомляет все потоки, заблокированные в ожидании атомарного объекта (public функция-элемент) | |
Константы | |
[static] (C++17) |
указывает, что тип всегда свободен от блокировок (public static константа-элемент) |
Специализированные функции-элементы
| атомарно добавляет аргумент к значению, хранящемуся в атомарном объекте, и получает значение, сохранённое ранее (public функция-элемент) | |
| атомарно вычитает аргумент из значения, хранящегося в атомарном объекте, и получает значение, сохранённое ранее (public функция-элемент) | |
| атомарно выполняет побитовое И между аргументом и значением атомарного объекта и получает значение, сохранённое ранее (public функция-элемент) | |
| атомарно выполняет побитовое ИЛИ между аргументом и значением атомарного объекта и получает значение, сохранённое ранее (public функция-элемент) | |
| атомарно выполняет побитовое исключающее ИЛИ между аргументом и значением атомарного объекта и получает значение, сохранённое ранее (public функция-элемент) | |
| увеличивает или уменьшает атомарное значение на единицу (public функция-элемент) | |
| добавляет, вычитает или выполняет побитовое И, ИЛИ, исключающее ИЛИ с атомарным значением (public функция-элемент) |
Примечание
Существуют эквиваленты шаблонов функций, не являющихся элементами, для всех функций-элементов std::atomic. Эти функции, не являющиеся элементами, могут быть дополнительно перегружены для типов, которые не являются специализациями std::atomic, но могут гарантировать атомарность. Единственный такой тип в стандартной библиотеке это std::shared_ptr<U>.
_Atomic это ключевое слово и используется для предоставления атомарных типов в C.
Реализации рекомендуются для обеспечения того, чтобы представление _Atomic(T) в C было таким же, как представление std::atomic<T> в C++ для каждого возможного типа T. Механизмы, используемые для обеспечения атомарности и упорядочивания памяти, должны быть совместимы.
В gcc и clang некоторые функции, описанные здесь, требуют связывания с -latomic.
Пример
#include <atomic>
#include <iostream>
#include <thread>
#include <vector>
std::atomic_int acnt;
int cnt;
void f()
{
for(int n = 0; n < 10000; ++n)
{
++acnt;
++cnt;
// Примечание: для этого примера достаточно ослабленно упопорядоченной памяти,
// например, acnt.fetch_add(1, std::memory_order_relaxed);
}
}
int main()
{
{
std::vector<std::jthread> pool;
for(int n = 0; n < 10; ++n)
pool.emplace_back(f);
}
std::cout << "Атомарный счётчик равен " << acnt << '\n'
<< "Неатомарный счётчик равен " << cnt << '\n';
}
Возможный вывод:
Атомарный счётчик равен 100000
Неатомарный счётчик равен 69696
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| LWG 2441 | c++11 | typedef'фы для атомарных версий необязательных целочисленных типов фиксированной ширины отсутствовали |
добавлены |
| LWG 3012 | c++11 | std::atomic<T> был разрешён длялюбых T, которые можно копировать только тривиально
|
такие специализации запрещены |
| WG не указан | c++11 | вывод аргументов шаблона для некоторых функций для атомарных типов может случайно вызвать ошибку; были предоставлены недопустимые операции с указателями |
спецификация была существенно переписана: добавлены определения типов элементов value_type и difference_type
|
Смотрите также
(C++11) |
свободный от блокировок логический атомарный тип (класс) |
(C++20) |
атомарный разделяемый указатель (специализация шаблона класса) |
(C++20) |
атомарный слабый указатель (специализация шаблона класса) |
Документация C по Атомарные типы
| |