C++如何在不使用锁、无法改用std::atomic时避免整数比较的竞态条件
解决方案
问题根源
原有线程2的代码直接读取var1、var2属于非原子普通内存访问,和其他线程的原子写入操作之间没有同步关系,属于典型的数据竞争,会触发C++标准定义的未定义行为。
可行方案
当前代码已经使用GCC内置的原子操作API,我们可以直接复用同体系的原子读取操作实现需求,无需加锁、也无需修改变量的原有int类型:
方案1:兼容旧版GCC的实现
利用__sync_fetch_and_add加0的操作实现原子读,和现有代码的API完全兼容,操作自带全内存屏障,保证可见性:
修改线程2的代码如下:
// 原子读取var1、var2的最新值 int v1 = __sync_fetch_and_add(&var1, 0); int v2 = __sync_fetch_and_add(&var2, 0); var3 = v1 > v2 ? v1 : v2;
方案2:更高性能的实现(GCC 4.7及以上版本支持)
使用更轻量的__atomic_load_n配合ACQUIRE内存序,开销低于全内存屏障,性能更优:
修改线程2的代码如下:
// ACQUIRE内存序保证读取到该变量之前所有的写入结果 int v1 = __atomic_load_n(&var1, __ATOMIC_ACQUIRE); int v2 = __atomic_load_n(&var2, __ATOMIC_ACQUIRE); var3 = v1 > v2 ? v1 : v2;
方案合规性说明
- 无锁实现:原子读操作的开销极低,远低于锁的开销,完全满足性能要求
- 无需修改原有变量定义:两个方案都直接操作原有int类型的
var1、var2,不需要改为std::atomic - 消除数据竞争:所有对
var1、var2的访问都变成了带同步语义的原子操作,完全消除了数据竞争 - 逻辑兼容:仅将原有非原子读替换为原子读,业务逻辑和原有代码完全一致,不会改变原有业务行为
内容的提问来源于stack exchange,提问作者spooja__
相关产品推荐
相关产品推荐

