作者:mobiledu2502876193 | 来源:互联网 | 2023-01-22 17:58
使用atomic_store存储的数据和使用atomic_load加载的数据是否总是一致?
具体来说:C11程序访问故意放置在现代Intel CPU上高速缓存行之间边界的64位数据.它使用atomic_store和atomic_load(from
)从多个线程(在不同的核心上运行)访问此数据.
数据是否总是显得一致,或者加载它(atomic_load)有时会有一些属于旧值的字节,以及属于更新值的其他字节?
以下是基本的结构和变量定义以及程序的有趣部分,它们在一个循环中,并行地从多个线程发生:
struct Data {
uint8_t bytes[CACHELINE__BYTECOUNT - 4];
atomic_uint_fast64_t u64;
} __attribute__((packed)) __attribute__((aligned ((CACHELINE__BYTECOUNT))));
#define VAL1 (0x1111111111111111)
#define VAL2 (0xFFFFFFFFFFFFFFFF)
static struct Data data = { .u64 = VAL1 };
...
for (uint32_t j = 0; j <1000; j++) {
atomic_store(&data.u64, VAL1);
atomic_store(&data.u64, VAL2);
}
const uint64_t val = atomic_load(&data.u64);
/* is 'val' always VAL1 or VAL2? */
(完全可运行的程序:https://gist.github.com/sinelaw/1230d4675d6a4fff394110f17e463954)
用gcc 6.3.0和clang 3.7检查它显示它不是原子的:
$ clang -std=c11 -Wall -Wextra /tmp/atomic.c -o /tmp/atomic -lpthread
$ /tmp/atomic
ERROR: oh no, got: 11111111FFFFFFFF
所以无论是程序中存在错误,还是我误解了
,或者编译器中存在错误.
1> Art..:
正确编写的程序无法获取未正确对齐的对象.正确对齐的int64无法跨越缓存行.
所以你的问题的答案是:你的程序中有一个错误.您通过使用非标准构造(__attribute__
)来破坏事物而故意引入的错误.
对于编译器来说,确保stdatomic适用于未对齐的值是很疯狂的,因为这需要一个全局锁,这是stdatomic特别要避免的.
@sinelaw这可能是使用`packed`的最糟糕的理由.在某些边缘情况下,`packed`很有用,但这不是其中之一.对此的警告将是完全多余的,因为每次使用`packed`时都应该发出警告,因为这是"打包"唯一的事情 - 它会打破对齐.唯一不会发出的是"打包"没有效果."填充"不是编译器用来搞定你的东西,它是在数据正确对齐后留下的东西(这就是为什么我不喜欢单词"padding").