例如,
atomic_int test(void)
{
atomic_int tmp = ATOMIC_VAR_INIT(14);
tmp = 47; // Looks like atomic_store
atomic_int mc; // Probably just uninitialised data
memcpy(&mc,&tmp,sizeof(mc)); // Probably equivalent to a copy
tmp = mc + 4; // Arithmetic
return tmp; // A copy - perhaps load then store
}
Clang 对这一切很满意。我已经阅读了标准的第 7.17 节,它说了很多关于内存模型和定义的函数(init、store、load 等)的内容,但没有提及任何关于常用操作(+、= 等)的内容。
同样有趣的是将
struct wot { atomic_int value; }
传递给函数的行为。
我愿意相信赋值的行为与原子加载相同,然后使用 memory_order_seq_cst 进行存储。
更乐观的是,我愿意相信结构体赋值、传递给函数、从函数返回甚至 memcpy 的行为也与在 memory_order_seq_cst 下仔细复制位模式相同。
不过,我找不到任何支持该标准信念的证据。原子原语的赋值和 memcpy 肯定有可能是未定义的行为。
原子基元上的基元操作应该如何表现?
谢谢!
对
_Atomic
限定的对象的操作(atomic_int
只是不同的写法)保证具有顺序一致性。您会发现每个操作数的语义部分末尾都提到了这一点。 (也许缺少提及作业。)
您的代码在两个地方不正确:初始化必须使用
ATOMIC_VAR_INIT
宏(7.17.2.1),并且 memcpy
未定义(大小可能不一致),尽管它可能适用于大多数架构。
还有线路
tmp = mc + 4; // Arithmetic
不符合您的评论所述。这不是对原子对象进行算术运算,而是加载后进行普通加法。更有趣的是
mc += 4; // Arithmetic
这是一个具有顺序一致性的原子操作。来自 C11 标准第 6.5.16.2 节:
E1op = E2 形式的 A 复合赋值 等价于简单赋值表达式 E1 = E1 op (E2),除了左值 E1 仅计算一次,并且相对于不确定序列函数调用时,复合赋值操作是单次求值。 如果 E1 具有原子类型,则复合赋值是具有
内存顺序语义的读-修改-写操作。memory_order_seq_cst