| Атомарный тип | Соответствующая специализация |
|---|---|
atomic_bool | std::atomic |
atomic_char | std::atomic |
atomic_schar | std::atomic |
atomic_uhar | std::atomic |
atomic_int | std::atomic |
atomic_uint | std::atomic |
atomic_short | std::atomic |
atomic_ushort | std::atomic |
atomic_long | std::atomic |
atomic_ulong | std::atomic |
atomic_llong | std::atomic |
atomic_ullong | std::atomic |
atomic_char16_t | std::atomic |
atomic_char32_t | std::atomic |
atomic_wchar_t | std::atomic |
Помимо основных атомарных типов, в стандартной библиотеке С++ определены также псевдонимы typedef для атомарных типов, соответствующих различным неатомарным библиотечным typedef, например std::size_t. Они перечислены в табл. 5.2.
Таблица 5.2. Соответствие между стандартными атомарными и встроенными typedef
Атомарный typedef | Соответствующий typedef из стандартной библиотеки |
|---|---|
atomic_int_least8_t | int_least8_t |
atomic_uint_least8_t | uint_least8_t |
atomic_int_least16_t | int_least16_t |
atomic_uint_least16_t | uint_least16_t |
atomic_int_least32_t | int_least32_t |
atomic_uint_least32_t | uint_least32_t |
atomic_int_least64_t | int_least64_t |
atomic_uint_least64_t | uint_least64_t |
atomic_int_fast8_t | int_fast8_t |
atomic_uint_fast8_t | uint_fast8_t |
atomic_int_fast16_t | int_fast16_t |
atomic_uint_fast16_t | uint_fast16_t |
atomic_int_fast32_t | int_fast32_t |
atomic_uint_fast32_t | uint_fast32_t |
atomic_int_fast64_t | int_fast64_t |
atomic_uint_fast64_t | uint_fast64_t |
atomic_intptr_t | intptr_t |
atomic_uintptr_t | uintptr_t |
atomic_size_t | size_t |
atomic_ptrdiff_t | ptrdiff_t |
atomic_intmax_t | intmax_t |
atomic_uintmax_t | uintmax_t |
Да уж, типов немало! Но есть простая закономерность — атомарный тип, соответствующий стандартному typedef T, имеет такое же имя с префиксом atomic_: atomic_T. То же самое относится и к встроенным типам с тем исключением, что signed сокращается до s, unsigned — до u, a long long — до llong. Вообще говоря, проще написать std::atomic для нужного вам типа T, чем пользоваться альтернативными именами.
Стандартные атомарные типы не допускают копирования и присваивания в обычном смысле, то есть не имеют копирующих конструкторов и операторов присваивания. Однако им все же можно присваивать значения соответствующих встроенных типов, и они поддерживают неявные преобразования в соответствующие встроенные типы. Кроме того, в них определены функции-члены load(), store(), exchange(), compare_exchange_weak() и compare_exchange_strong(). Поддерживаются также составные операторы присваивания (там, где это имеет смысл) +=, -=, *=, |= и т.д., а для целочисленных типов и специализаций std::atomic<> для указателей — еще и операторы ++ и --. Этим операторам соответствуют также именованные функции-члены с идентичной функциональностью: fetch_add(), fetch_or() и т.д. Операторы присваивания возвращают сохраненное значение, а именованные функции-члены — значение, которое объект имел до начала операции. Это позволяет избежать потенциальных проблем, связанных с тем, что обычно операторы присваивания возвращают ссылку на объект в левой части. Чтобы получить из такой ссылки сохраненное значение, программа должна была бы выполнить еще одну операцию чтения, но тогда между присваиванием и чтением другой поток мог бы модифицировать значение, открывая дорогу гонке.
Но шаблон класса std::atomic<> — не просто набор специализаций. В нем есть основной шаблон, который можно использовать для создания атомарного варианта пользовательского типа. Поскольку это обобщенный шаблон класса, определены только операции load(), store() (а также присваивание значения пользовательского типа и преобразования в пользовательский тип), exchange(), compare_exchange_weak() и compare_exchange_strong().