原子操作
内容介绍
std::atomic 用来表达不可被线程打断的简单读写或自增操作。它适合计数器、状态标志、停止标志等简单共享状态。
原子计数器
#include <atomic>
#include <iostream>
#include <thread>
#include <vector>
int main() {
std::atomic<int> counter = 0;
std::vector<std::thread> threads;
for (int i = 0; i < 4; ++i) {
threads.emplace_back([&] {
for (int j = 0; j < 10000; ++j) {
++counter;
}
});
}
for (auto& t : threads) {
t.join();
}
std::cout << counter.load() << '\n';
}停止标志
std::atomic<bool> stop = false;
std::thread worker([&] {
while (!stop.load()) {
// do work
}
});
stop.store(true);
worker.join();更现代的取消方式见 cpp协作取消。
最佳代码实践
- 简单计数器和标志位可以用
atomic。 - 复杂不变量仍然用
mutex。 - 多个变量需要保持一致时,不要用多个 atomic 硬拼。
- 默认内存序
memory_order_seq_cst最保守,初学阶段不要轻易手写弱内存序。
常见错误用法
std::atomic<int> a = 0;
std::atomic<int> b = 0;
// 误以为 a 和 b 的组合状态自动一致
a.store(1);
b.store(1);问题:单个原子变量的操作是原子的,多个变量之间的业务不变量不是自动原子的。
注意事项
atomic不是“无锁万能解法”。- 原子代码更难证明正确,优先保证可读性。
- 无锁结构需要非常强的内存模型知识,初学阶段不建议手写。
学习路径
- 上一节:cpp条件变量
- 当前阶段:cpp多线程
- 下一节:cppfuture和promise