memory_order::acquire在read-modify-write操作中的作用与test_and_set疑问
关于
std::atomic_flag::test_and_set使用memory_order::acquire的内存语义解析 首先明确核心结论:当test_and_set指定memory_order::acquire时,这个读改写(RMW)操作的加载部分遵循acquire语义,存储部分遵循relaxed语义——既不等同于memory_order::acq_rel,存储部分也不会默认使用seq_cst。
具体语义拆解
test_and_set本质是原子的"读取当前值 + 设置为true"操作:
- 加载阶段(读取flag值):采用acquire语义,确保:
- 临界区的所有代码不会被处理器重排到这个加载操作之前;
- 当前线程能看到所有其他线程对该flag执行
release语义操作(比如clear(release))之前的所有内存写入。
- 存储阶段(设置flag为true):采用relaxed语义,仅保证该存储操作本身是原子的,不会对其他内存操作的顺序产生额外的同步约束——因为锁的"上锁"动作不需要向其他线程同步任何数据,只需要原子占据锁即可。
对疑问的澄清
是否等同于
acq_rel?
不是。memory_order::acq_rel要求RMW操作的加载部分是acquire,存储部分是release;而这里的存储是relaxed,没有release的同步效果。存储部分是否默认用
seq_cst?
只有当你不指定内存序参数时,test_and_set才会默认使用memory_order::seq_cst。一旦显式指定了acquire,存储阶段就会遵循relaxed语义,而非seq_cst。
为什么锁场景这么用是合理的
在你的锁代码中:
std::atomic_flag lock; // ... while (lock.test_and_set(std::memory_order::acquire)) {} // critical section lock.clear(std::memory_order::release);
test_and_set(acquire)的acquire语义保证临界区能看到其他线程释放锁前的所有操作;clear(release)的release语义负责把当前线程临界区的所有写入同步给后续获取锁的线程。
这种搭配是标准的"acquire-release"锁实现,足够保证同步且比seq_cst性能更好。
内容的提问来源于stack exchange,提问作者Jan Schultke
相关产品推荐
相关产品推荐

