arm64弱内存模型:为什么这个断言(assert(x == 1))不会失败

编程语言 2026-07-08

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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章