cpu会将STORE指令重新排序到同一地址吗?

时间:2018-12-19 05:25:58

标签: c multithreading assembly cpu-architecture cpu-cache

给出以下代码,CPU将对STORE a和STORE b重新排序吗?根据代码逻辑,a和b是独立的。

if (0 == system("$ssh $user\@$host [ -d $destination_path ]")) {
    print "Is a directory.\n";
} else {
    print "Is not a directory.\n";
}

2 个答案:

答案 0 :(得分:3)

您的问题几乎没有意义。

int* __attribute__ ((noinline)) GetMemAddr(int index) {
    static int data[10];
    return &data[0];
}

void fun() {
    int *a=GetMemAddr(1); //use different args to get same address to avoid optimiztion
    int *b=GetMemAddr(2);
    *a=1;
    *b=3;
}

compiled with GCC 7.3 and -O3完全消除了对GetMemAddr的第一次调用,因为它没有副作用。它也省略了分配*a=1noinline表示该函数不得内联。这并不意味着完全需要调用它。

实际上避免省略的唯一正确方法是将ab声明为volatile int *。这样,商店也将保持秩序。但是,仍然不能以任何方式保证这些存储是 atomic ,因此另一个线程可以看到有趣的事情-对于那些需要使用C11原子功能或编译器扩展/保证的人。

答案 1 :(得分:1)

CPU可以重新排序两个存储,只要它不违反CPU必须提供的任何保证即可。编译器的工作是为CPU生成代码,这不允许编译器进行优化,从而导致所生成的代码违反C标准。换句话说,C编译器采用它承诺将根据C标准的规则运行的代码,并通过依赖于CPU将其转换为实际上将根据C标准的规则运行的汇编代码。按照其体系结构规范的规则运行。

因此,如果这两个存储恰好位于相同的内存位置,则不可能进行“优化”,从而无法从同一线程观察到错误的结果。这将违反C标准,因此,不间断的编译器将生成不间断的CPU不执行此操作所需的任何代码。但是,除非平台的线程标准说了一些不同(我所不知道的事情),否则没有什么能阻止可能导致其他线程看到奇怪的中间结果的优化。

如果要跨线程保证,则必须使用原子操作,互斥量或平台为此提供的任何其他功能。如果您只希望代码能够正常工作,则需要特定于平台的知识,以了解平台实际能够执行的优化以及在该平台上禁用它们的方法(volatile,编译器标志等)