如何在C++中无锁CAS 64位变量的低32位?
问题
我有一个64位共享变量,某线程希望对该变量的低32位执行CAS操作,同时忽略高32位的变化。是否存在可移植的无锁实现方式?另外,如下代码是否可行,是否会违反严格别名规则或C++对象模型?
union { std::atomic<uint64_t> desc; struct { std::atomic<uint32_t> ldesc; std::atomic<uint32_t> hdesc; }; } variable; variable.desc = 0; uint32_t x = 0; variable.ldesc.compare_exchange_weak(x, 1);
可移植的无锁实现方案
当然有,核心思路是借助完整的64位原子变量来实现低32位的CAS,具体步骤和代码如下:
- 读取整个64位原子变量的当前值
- 提取低32位和预期值对比,不匹配则直接返回失败
- 若匹配,构造新的64位值:保留原高32位,替换低32位为目标值
- 对整个64位变量执行CAS操作,失败则循环重试
#include <atomic> #include <cstdint> std::atomic<uint64_t> shared_var = 0; bool cas_low_32_bits(uint32_t expected_low, uint32_t desired_low) { uint64_t current_full = shared_var.load(std::memory_order_acquire); do { uint32_t current_low = static_cast<uint32_t>(current_full); if (current_low != expected_low) { expected_low = current_low; return false; } uint64_t new_full = (current_full & 0xFFFFFFFF00000000ULL) | static_cast<uint64_t>(desired_low); } while (!shared_var.compare_exchange_weak(current_full, new_full, std::memory_order_release, std::memory_order_acquire)); return true; }
这种方案完全遵循C++标准,不依赖任何平台特定逻辑,在所有支持std::atomic<uint64_t>的平台上都能稳定工作。
你给出的代码存在的问题
这段代码属于未定义行为,完全不符合C++标准,具体问题如下:
- 违反union活跃成员规则:C++标准规定,union同一时间只能有一个活跃成员。你初始化了
variable.desc(std::atomic<uint64_t>类型)后,该成员成为活跃成员,此时访问ldesc和hdesc属于访问不活跃的union成员,是标准明确禁止的操作。 - 违反严格别名规则:
std::atomic<uint64_t>与两个std::atomic<uint32_t>是完全不同的类型,通过union重叠存储后交叉访问,会触发严格别名违规,编译器可能生成错误的机器码(比如忽略内存同步、错误优化读写逻辑)。 - 原子对象布局无保证:
std::atomic类型的内部实现依赖平台,标准不保证std::atomic<uint64_t>能拆分为两个独立的std::atomic<uint32_t>。比如部分平台的原子操作需要特定对齐要求,或内部包含同步元数据,这种拆分逻辑根本不成立。
哪怕在某个平台上这段代码碰巧能运行,也不具备可移植性,随时可能因编译器版本、平台变化导致崩溃或逻辑错误。
内容的提问来源于stack exchange,提问作者blonded04
相关产品推荐
相关产品推荐

