什么是原子操作?
"原子操作" 是不可分割的操作------ 要么完整执行,要么完全不执行,中间不会被其他线程打断。
例如:普通 int count++ 是 "读→改→写" 三步,多线程下会出现数据竞争;而 std::atomic<int> count; count++ 是一步原子操作,线程安全。
底层原理
std::atomic 依赖硬件 + 软件实现线程安全:
- 硬件原子指令 :现代 CPU(x86/ARM)提供
CMPXCHG(CAS)、原子加减等指令,将 "读 - 改 - 写" 封装为一步不可分割的操作; - 缓存一致性协议:如 MESI 协议,保证一个 CPU 修改原子变量后,其他 CPU 的缓存会同步更新;
- C++ 封装 :
std::atomic是硬件原子指令的 C++ 语法封装,无需写汇编即可使用。
std::atomic 类模板概述
std::atomic 是类模板 ,仅支持平凡可复制类型 (如 int、double、指针),不支持 std::string 等复杂类型。
类模板简化声明:
template <class T>
struct atomic {
// 核心成员函数(下文详解)
};
常用特化:std::atomic<int>、std::atomic<long>、std::atomic<char*> 等。
1. 原子读:load()
-
函数声明 :
T load(std::memory_order order = std::memory_order_seq_cst) const noexcept; -
参数 :
order:内存顺序(默认memory_order_seq_cst,最严格的全局一致顺序);
-
作用:原子地读取原子变量的当前值,保证读到最新结果;
-
返回值 :原子变量的当前值(类型为
T)。
2. 原子写:store()
-
函数声明 :
void store(T desired, std::memory_order order = std::memory_order_seq_cst) noexcept; -
参数 :
desired:想要设置给原子变量的新值;order:内存顺序(默认memory_order_seq_cst);
-
作用 :原子地将原子变量的值设为
desired,写操作不会被其他线程打断; -
返回值:无。
3. 原子加:fetch_add()
T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
- 参数 :
arg:要给原子变量增加的数值;order:内存顺序(默认memory_order_seq_cst);
- 作用 :原子地将原子变量的值 加
arg,操作不可分割; - 返回值 :原子变量在 "加
arg之前" 的旧值(类型为T)。
4. 原子减:fetch_sub()
T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
- 参数 :
arg:要给原子变量减少的数值;order:内存顺序(默认memory_order_seq_cst);
- 作用 :原子地将原子变量的值 减
arg,操作不可分割; - 返回值 :原子变量在 "减
arg之前" 的旧值(类型为T)。
5. compare_exchange_weak
bool compare_exchange_weak(
T& expected,
T desired,
std::memory_order success = std::memory_order_seq_cst,
std::memory_order failure = std::memory_order_seq_cst
) noexcept;
- 参数 :
expected:引用类型,表示 "期望原子变量当前的值";desired:若原子变量值等于expected,要设置的新值;success:CAS 成功时使用的内存顺序;failure:CAS 失败时使用的内存顺序;
- 作用 :
- 比较原子变量当前值与
expected; - 若相等 :将原子变量设为
desired,返回true; - 若不相等 :将
expected更新为原子变量的当前值,返回false;(注:可能 "虚假失败",需配合while循环使用);
- 比较原子变量当前值与
- 返回值 :
bool,true表示 CAS 成功,false表示失败。
6. compare_exchange_strong
bool compare_exchange_strong(
T& expected,
T desired,
std::memory_order success = std::memory_order_seq_cst,
std::memory_order failure = std::memory_order_seq_cst
) noexcept;
- 参数 :与
compare_exchange_weak完全相同; - 作用 :与
compare_exchange_weak逻辑一致,但不会虚假失败; - 返回值 :
bool,true表示 CAS 成功,false表示失败。
7. 自增 / 自减运算符(语法糖)
std::atomic<T> 重载了 ++/--,本质是 fetch_add(1)/fetch_sub(1) 的简化:
- 前置自增:
T& operator++() noexcept;(返回新值); - 后置自增:
T operator++(int) noexcept;(返回旧值); - 前置自减:
T& operator--() noexcept;(返回新值); - 后置自减:
T operator--(int) noexcept;(返回旧值)。
特殊原子类型:std::atomic_flag
std::atomic_flag 是强制免锁的原子布尔类型(C++ 标准要求),仅用于实现自旋锁。
类简化声明:
struct atomic_flag {
// 核心成员函数
};
atomic_flag 核心成员函数
1. test_and_set()
-
函数声明 :
bool test_and_set(std::memory_order order = std::memory_order_seq_cst) noexcept; -
参数 :
order:内存顺序(默认memory_order_seq_cst);
-
作用 :原子地将
atomic_flag设为true; -
返回值 :
atomic_flag在 "设为true之前" 的旧值(bool类型)。
2. clear()
-
函数声明 :
void clear(std::memory_order order = std::memory_order_seq_cst) noexcept; -
参数 :
order:内存顺序(默认memory_order_seq_cst);
-
作用 :原子地将
atomic_flag设为false; -
返回值:无。
内存顺序(std::memory_order)
std::atomic 函数的 order 参数控制内存同步行为,新手常用 3 种:
memory_order_relaxed:- 作用:仅保证原子性,无同步 / 顺序约束;
- 适用场景:计数器等无需同步的场景。
memory_order_acquire:- 作用:当前操作前的读写不会被重排序到之后;
- 适用场景:加载操作(配合
release同步数据)。
memory_order_release:- 作用:当前操作后的读写不会被重排序到之前;
- 适用场景:存储操作(配合
acquire同步数据)。
memory_order_seq_cst(默认) :- 作用:全局顺序一致,所有线程看到的操作顺序相同;
- 适用场景:需要强一致性的场景(性能略低)。
应用场景
线程安全计数器
用 fetch_add() 实现:
#include <atomic>
#include <thread>
#include <vector>
#include <iostream>
using namespace std;
atomic<int> atomic_cnt = 0; // 原子计数器
void add() {
for (int i = 0; i < 10000; ++i) {
// 原子加1,用relaxed内存顺序(更快)
atomic_cnt.fetch_add(1, memory_order_relaxed);
}
}
int main() {
vector<thread> threads;
for (int i = 0; i < 4; ++i) {
threads.emplace_back(add);
}
for (auto& t : threads) t.join();
cout << "原子计数器结果:" << atomic_cnt.load() << endl; // 输出40000
return 0;
}
用 atomic_flag 实现自旋锁
#include <atomic>
#include <thread>
#include <vector>
#include <iostream>
using namespace std;
class SpinLock {
private:
atomic_flag flag = ATOMIC_FLAG_INIT; // 初始化为false
public:
void lock() {
// 循环直到拿到锁:test_and_set返回false表示成功
while (flag.test_and_set(memory_order_acquire));
}
void unlock() {
flag.clear(memory_order_release); // 释放锁
}
};
SpinLock lock;
int shared_val = 0;
void worker() {
lock.lock();
for (int i = 0; i < 10000; ++i) {
shared_val++;
}
lock.unlock();
}
int main() {
vector<thread> threads;
for (int i = 0; i < 4; ++i) {
threads.emplace_back(worker);
}
for (auto& t : threads) t.join();
cout << "共享变量结果:" << shared_val << endl; // 输出40000
return 0;
}
多线程头插链表
#include<iostream>
#include<chrono>
#include<atomic>
#include<thread>
#include<vector>
using namespace std;
struct Node {
int _val;
Node* _next;
Node(int val,Node*next):_val(val),_next(next){}
};
atomic<Node*>list;
void push_head(int val) {
this_thread::sleep_for(chrono::seconds(1));
Node* old_ = list.load();
Node* new_=new Node( val, old_ );
while (!list.compare_exchange_weak(old_, new_))
new_->_next = old_;
}
int main() {
vector<thread>vt;
for (int i = 0; i < 5; i++) {
vt.emplace_back(push_head,i);
}
for (auto& it : vt)it.join();
Node* n = list.load();
while (n) {
cout << n->_val << " ";
n = n->_next;
}
}

atomic_flag vs atomic<bool>
| 维度 | std::atomic_flag |
std::atomic<bool> |
|---|---|---|
| 类声明 | struct atomic_flag; |
template<> struct atomic<bool>; |
| 免锁性 | 强制免锁(C++ 标准要求) | 主流平台免锁,小众平台可能用锁模拟 |
| 核心函数 | 1. bool test_and_set(memory_order);2. void clear(memory_order); |
1. bool load(memory_order);2. void store(bool, memory_order);3. bool compare_exchange_weak(...) |
| 初始化 | 必须用 ATOMIC_FLAG_INIT(默认 false) |
直接赋值(如 atomic<bool> f = true;) |
| 核心用途 | 实现自旋锁 | 通用原子布尔标记(开关、状态位) |
weak vs strong 核心差异
| 维度 | compare_exchange_weak |
compare_exchange_strong |
|---|---|---|
| 核心特性 | 可能发生虚假失败(Spurious Failure) | 无虚假失败,"相等则必成功" |
| 虚假失败定义 | 即使原子变量值 == expected,也可能返回 false |
只要原子变量值 == expected,一定返回 true |
| 性能 | 更快(底层适配硬件指令,减少锁 / 重试逻辑) | 略慢(需额外逻辑避免虚假失败) |