原子操作

内容介绍

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 不是“无锁万能解法”。
  • 原子代码更难证明正确,优先保证可读性。
  • 无锁结构需要非常强的内存模型知识,初学阶段不建议手写。

学习路径