arm64弱内存模型:为什么这个断言(assert(x == 1))不会失败
Thread 1: x = 1; y = 1;
Thread 2: if (y == 1) assert(x == 1);
Thread 1可能顺序错乱。但 assert 在我的 arm64 开发板上不会报错。
完整代码(在 arm64 开发板上构建并运行。没有 assert 失败信息):
#include <pthread.h>
#include <stdio.h>
#define assert(cond) if (!(cond)) printf("assert: %s failed\n", #cond)
volatile unsigned long x, y;
void *f1(void *)
{
while (1) {
if (y == 0) {
x = 1;
y = 1;
}
}
}
void *f2(void *)
{
while (1) {
if (y == 1) {
assert(x == 1);
x = 0;
y = 0;
}
}
}
void main()
{
pthread_t a, b;
pthread_create(&a, NULL, f1, NULL);
pthread_create(&b, NULL, f2, NULL);
pthread_join(a, NULL);
pthread_join(b, NULL);
}
解决方案
你看不到内存更新顺序不同的原因,是因为你的两个变量恰好位于同一个缓存行(纯属巧合);在ARM架构上,据我记得(已经好几年没碰这个了),唯一可能导致乱序的操作来自缓存同步的方式(其他架构可能有写入缓冲区,甚至可能在同一个缓存行内引发有序性问题)。
在你的测试代码中,将从:
volatile unsigned long x, y;
改为:
volatile unsigned long v[256];
#define x v[0]
#define y v[64]
(同时修改main的返回类型),你就会看到你期望看到的结果:
% cc -std=c23 -o foo foo.c && ./foo
assert: x == 1 failed
assert: x == 1 failed
assert: x == 1 failed
assert: x == 1 failed
assert: x == 1 failed
^C
% uname -smv
Darwin Darwin Kernel Version 25.3.0: Wed Jan 28 20:54:55 PST 2026; root:xnu-12377.91.3~2/RELEASE_ARM64_T8132 arm64
将其改为 #define y v[1] 再次运行,你会看到断言又消失了。
你甚至可以通过调整偏移量来尝试找出你CPU的缓存行大小。我用64,因为它在可预见的未来肯定够用。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。