我有一个 64 位共享变量,一个线程想要 CAS 该字的低 32 位,同时忽略该字的高 32 位的更改。有没有一种便携式的免锁方式?
这样的东西是否有效,或者它违反了与严格别名或 C++ 对象模型相关的内容?:
union {
std::atomic<std::int64_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);
在当前标准中指定的 C++ 内存/对象模型中无法执行此操作。
如果原子对象是 64 位宽,则只有原语可以读取整个 64 位对象的值(可能除了逐字节读取当前未指定的对象表示形式)。
即使对于非原子访问甚至标量对象也是如此。即使成员是非原子的,您的示例也会有未定义的行为。 (从技术上讲,根据标准,匿名
struct
成员不是有效的语法。)
您可以使用
std::start_lifetime_as
将对象替换为不同类型的新对象,但是 必须 在线程之间进行外部同步,然后再进行访问,因为旧类型不再可能了。
话虽这么说,编译器通常在非原子情况下支持联合类型双关,以与 C 兼容。我不完全确定 C 是否允许原子类型的类型双关,或者它的内存模型是否允许您正在尝试的操作要做。