std::atomic

来自cppreference.com
< cpp‎ | atomic
 
 
并发支持库
线程
(C++11)
(C++20)
(C++20)
this_thread 命名空间
(C++11)
(C++11)
(C++11)
互斥
(C++11)
(C++11)  
通用锁管理
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
条件变量
(C++11)
信号量
闩与屏障
(C++20)
(C++20)
未来体
(C++11)
(C++11)
(C++11)
(C++11)
安全回收
(C++26)
(C++26)
风险指针





原子类型
atomic
(C++11)
(C++20)
原子类型的初始化
(C++11)(C++20 中弃用)
(C++11)(C++20 中弃用)
内存定序
原子操作的自由函数
原子标志的自由函数
 
 
在标头 <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 既不可复制也不可移动。

<stdatomic.h> 中提供了兼容性宏 _Atomic,使得两者均良构时 _Atomic(T) 等同于 std::atomic<T>

包含 <stdatomic.h> 时未指定命名空间 std 中的任何声明是否可用。

(C++23 起)

特化

主模板

std::atomic 模板可用任何满足可复制构造 (CopyConstructible) 可复制赋值 (CopyAssignable) 可平凡复制 (TriviallyCopyable) 类型 T 实例化。如果下列任何值是 false,那么程序非良构:

struct Counters { int a; int b; }; // 用户定义的可平凡复制类型
std::atomic<Counters> cnt;         // 为用户定义的类型而特化

std::atomic<bool> 使用的是主模板。它保证是标准布局结构体,并且具有平凡析构函数

部分特化

标准库为下列类型提供 std::atomic 模板的特化,它们拥有主模板所不拥有的额外属性:

2) 针对所有指针类型的部分特化 std::atomic<U*>。这些特化拥有标准布局、平凡默认构造函数 (C++20 前)和平凡析构函数。除了为所有原子类型提供的操作外,这些特化额外支持适合指针类型的原子算术运算,例如 fetch_addfetch_sub
3,4) 针对 std::shared_ptrstd::weak_ptr 提供的部分特化 std::atomic<std::shared_ptr<U>>std::atomic<std::weak_ptr<U>>

细节见 std::atomic<std::shared_ptr>std::atomic<std::weak_ptr>

(C++20 起)

对整数类型的特化

以下列整数类型之一实例化时,std::atomic 提供适合于整数类型的额外原子操作,例如 fetch_addfetch_subfetch_andfetch_orfetch_xor

  • 字符类型 charchar8_t (C++20 起)char16_tchar32_twchar_t
  • 标准有符号整数类型:signed charshortintlonglong long
  • 标准无符号整数类型:unsigned charunsigned shortunsigned intunsigned longunsigned long long
  • 标头 <cstdint> 中的各 typedef 所需的任何额外整数类型。

另外,结果的 std::atomic<整数> 特化拥有标准布局、平凡默认构造函数 (C++20 前)和平凡析构函数。定义有符号整数算术为使用补码;无未定义的结果。

对浮点类型的特化

以无 cv 限定的浮点类型(floatdoublelong double 和无 cv 限定的扩展浮点类型 (C++23 起))之一实例化时,std::atomic 提供适合于浮点类型的额外原子操作,例如 fetch_addfetch_sub

另外,结果的 std::atomic<浮点> 特化拥有标准布局和平凡析构函数。

无操作导致未定义行为,即使结果不能以浮点类型表示。有效的浮点环境可能与调用方线程的浮点环境不同。

(C++20 起)

成员类型

成员类型 定义
value_type T (无论是否特化)
difference_type value_type (仅对 atomic<整数> atomic<浮点> (C++20 起) 特化)
std::ptrdiff_t (仅对 std::atomic<U*> 特化)

std::atomic 主模板中,或对 std::shared_ptrstd::weak_ptr 的部分特化中,未定义 difference_type

成员函数

构造原子对象
(公开成员函数)
存储值于原子对象
(公开成员函数)
检查原子对象是否免锁
(公开成员函数)
原子地以非原子实参替换原子对象的值
(公开成员函数)
原子地获得原子对象的值
(公开成员函数)
从原子对象加载值
(公开成员函数)
原子地替换原子对象的值并获得它先前持有的值
(公开成员函数)
原子地比较原子对象与非原子实参的值,相等时进行原子交换,不相等时进行原子加载
(公开成员函数)
(C++20)
阻塞线程直到被提醒且原子值更改
(公开成员函数)
提醒至少一个在原子对象上的等待中阻塞的线程
(公开成员函数)
提醒所有在原子对象上的等待中阻塞的线程
(公开成员函数)

常量

[静态] (C++17)
指示该类型是否始终免锁
(公开静态成员常量)

特化成员函数

为整数、浮点 (C++20 起)和指针类型特化
原子地将实参加到存储于原子对象的值上,并返回先前保有的值
(公开成员函数)
原子地从存储于原子对象的值减去实参,并获得先前保有的值
(公开成员函数)
与原子值进行加、减
(公开成员函数)
仅为整数和指针类型特化
(C++26)
原子地进行实参和原子对象的值的 std::max,并获得先前保有的值
(公开成员函数)
(C++26)
原子地进行实参和原子对象的值的 std::min,并获得先前保有的值
(公开成员函数)
令原子值增加或减少一
(公开成员函数)
仅为整数类型特化
原子地进行实参和原子对象的值的逐位与,并获得先前保有的值
(公开成员函数)
原子地进行实参和原子对象的值的逐位或,并获得先前保有的值
(公开成员函数)
原子地进行实参和原子对象的值的逐位异或,并获得先前保有的值
(公开成员函数)
与原子值进行逐位与、或、异或
(公开成员函数)

类型别名

bool 和所有上面列出的整数类型提供如下类型别名:

所有 std::atomic<整数> 的别名
atomic_bool
(C++11)
std::atomic<bool>
(typedef)
atomic_char
(C++11)
std::atomic<char>
(typedef)
atomic_schar
(C++11)
std::atomic<signed char>
(typedef)
atomic_uchar
(C++11)
std::atomic<unsigned char>
(typedef)
atomic_short
(C++11)
std::atomic<short>
(typedef)
atomic_ushort
(C++11)
std::atomic<unsigned short>
(typedef)
atomic_int
(C++11)
std::atomic<int>
(typedef)
atomic_uint
(C++11)
std::atomic<unsigned int>
(typedef)
atomic_long
(C++11)
std::atomic<long>
(typedef)
atomic_ulong
(C++11)
std::atomic<unsigned long>
(typedef)
atomic_llong
(C++11)
std::atomic<long long>
(typedef)
atomic_ullong
(C++11)
std::atomic<unsigned long long>
(typedef)
atomic_char8_t
(C++20)
std::atomic<char8_t>
(typedef)
atomic_char16_t
(C++11)
std::atomic<char16_t>
(typedef)
atomic_char32_t
(C++11)
std::atomic<char32_t>
(typedef)
atomic_wchar_t
(C++11)
std::atomic<wchar_t>
(typedef)
atomic_int8_t
(C++11)(可选)
std::atomic<std::int8_t>
(typedef)
atomic_uint8_t
(C++11)(可选)
std::atomic<std::uint8_t>
(typedef)
atomic_int16_t
(C++11)(可选)
std::atomic<std::int16_t>
(typedef)
atomic_uint16_t
(C++11)(可选)
std::atomic<std::uint16_t>
(typedef)
atomic_int32_t
(C++11)(可选)
std::atomic<std::int32_t>
(typedef)
atomic_uint32_t
(C++11)(可选)
std::atomic<std::uint32_t>
(typedef)
atomic_int64_t
(C++11)(可选)
std::atomic<std::int64_t>
(typedef)
atomic_uint64_t
(C++11)(可选)
std::atomic<std::uint64_t>
(typedef)
atomic_int_least8_t
(C++11)
std::atomic<std::int_least8_t>
(typedef)
atomic_uint_least8_t
(C++11)
std::atomic<std::uint_least8_t>
(typedef)
atomic_int_least16_t
(C++11)
std::atomic<std::int_least16_t>
(typedef)
atomic_uint_least16_t
(C++11)
std::atomic<std::uint_least16_t>
(typedef)
atomic_int_least32_t
(C++11)
std::atomic<std::int_least32_t>
(typedef)
atomic_uint_least32_t
(C++11)
std::atomic<std::uint_least32_t>
(typedef)
atomic_int_least64_t
(C++11)
std::atomic<std::int_least64_t>
(typedef)
atomic_uint_least64_t
(C++11)
std::atomic<std::uint_least64_t>
(typedef)
atomic_int_fast8_t
(C++11)
std::atomic<std::int_fast8_t>
(typedef)
atomic_uint_fast8_t
(C++11)
std::atomic<std::uint_fast8_t>
(typedef)
atomic_int_fast16_t
(C++11)
std::atomic<std::int_fast16_t>
(typedef)
atomic_uint_fast16_t
(C++11)
std::atomic<std::uint_fast16_t>
(typedef)
atomic_int_fast32_t
(C++11)
std::atomic<std::int_fast32_t>
(typedef)
atomic_uint_fast32_t
(C++11)
std::atomic<std::uint_fast32_t>
(typedef)
atomic_int_fast64_t
(C++11)
std::atomic<std::int_fast64_t>
(typedef)
atomic_uint_fast64_t
(C++11)
std::atomic<std::uint_fast64_t>
(typedef)
atomic_intptr_t
(C++11)(可选)
std::atomic<std::intptr_t>
(typedef)
atomic_uintptr_t
(C++11)(可选)
std::atomic<std::uintptr_t>
(typedef)
atomic_size_t
(C++11)
std::atomic<std::size_t>
(typedef)
atomic_ptrdiff_t
(C++11)
std::atomic<std::ptrdiff_t>
(typedef)
atomic_intmax_t
(C++11)
std::atomic<std::intmax_t>
(typedef)
atomic_uintmax_t
(C++11)
std::atomic<std::uintmax_t>
(typedef)
特殊用途类型的别名
atomic_signed_lock_free
(C++20)
免锁且对于等待/提醒最高效的有符号整数原子类型
(typedef)
atomic_unsigned_lock_free
(C++20)
免锁且对于等待/提醒最高效的无符号整数原子类型
(typedef)

注意:std::atomic_intN_tstd::atomic_uintN_tstd::atomic_intptr_tatomic_uintptr_t 分别在当且仅当定义了 std::intN_tstd::uintN_tstd::intptr_tstd::uintptr_t 时才会有定义。

std::atomic_signed_lock_freestd::atomic_unsigned_lock_free 在独立实现中可选。

(C++20 起)

注解

存在等价于 std::atomic 所有成员函数的非成员函数模板。这些非成员函数可以额外对非 std::atomic 特化的类型重载,但不能保证原子性。标准库中仅有的这种类型是 std::shared_ptr<U>

C 中 _Atomic关键词并用于提供原子类型

推荐实现确保对于每个可能的类型 T,C 中 _Atomic(T) 的表示与 C++ 中 std::atomic<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 容许 禁止这种特化
LWG 3949 C++17 C++17 意外地丢失了要求 std::atomic<bool> 具有平凡析构函数的说明 已补回
P0558R1 C++11 某些原子类型函数的模板实参推导可能意外失败;
提供了非法指针操作
实质上重写了规范:提供成员 typedef
value_typedifference_type

参阅

免锁的布尔原子类型
(类)
原子共享指针
(类模板特化)
原子弱指针
(类模板特化)