一、内存模型的核心问题与原子操作背景
C++11之前,多线程编程面临三大挑战:指令重排导致逻辑错误、可见性问题引发数据不一致、数据竞争产生未定义行为。原子操作通过将读写操作封装为不可分割的单元,确保在多核环境下:
原子性:操作要么全部完成,要么完全不执行(如x++分解为load-add-store的原子组合)
可见性:修改立即对其他线程可见,避免缓存不一致问题
有序性:通过happens-before关系约束操作顺序
二、C++11内存模型关键机制
1. 原子类型体系
标准库提供std::atomic模板类及其特化版本,支持基本类型和指针的原子操作:
std::atomic<int> counter(0); // 原子计数器 std::atomic_flag flag = ATOMIC_FLAG_INIT; // 二值标志
所有原子操作通过底层硬件指令(如x86的LOCK前缀)实现,通常仅需1-2条CPU指令。
2. 内存顺序控制
通过std::memory_order参数灵活控制同步强度:
内存顺序
描述
适用场景
seq_cst
最强顺序保证
默认模式,全局同步
acquire/release
建立线程间同步点
生产者-消费者队列
relaxed
仅保证原子性
无依赖的计数器
3. 改动序列一致性
程序运行时,每个对象的写操作构成改动序列,所有线程必须对同一对象的序列达成一致。原子操作通过以下规则维护一致性:
线程读取对象后,后续读必须获取最新值
写操作必须出现在后续写之前
跨对象操作仅保证相对顺序
三、典型应用场景与性能权衡
高性能计数器
std::atomic<long long> total{0}; thread t1([&]{ for (int i=0; i<1e6;) total.fetch_add(i++, std::memory_order_relaxed); }); thread t2([&]{ for (int i=0; i<1e6;) total.fetch_add(i++, std::memory_order_relaxed); });
relaxed模式消除锁开销,但需确保操作间无依赖。
线程安全队列
std::atomic<int> head{0}, tail{0}; void enqueue(int val) { int next = tail.load(std::memory_order_relaxed); buffer[next] = val; tail.store(next + 1, std::memory_order_release); }
通过release语义确保写入对其他线程立即可见。
四、与锁机制的对比优势
特性
原子操作
互斥锁
开销
1-2条指令
系统调用+上下文切换
死锁
无风险
可能发生
适用性
简单数据
复杂临界区
五、开发注意事项
避免原子类型拷贝/赋值(所有原子类型禁止复制)
慎用is_lock_free检测(仅std::atomic_flag始终无锁)
复合操作需结合compare_exchange实现(如CAS算法)
1839

被折叠的 条评论
为什么被折叠?



