给出以下代码,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";
}
答案 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=1
。 noinline
表示该函数不得内联。这并不意味着完全需要调用它。
实际上避免省略的唯一正确方法是将a
和b
声明为volatile int *
。这样,商店也将保持秩序。但是,仍然不能以任何方式保证这些存储是 atomic ,因此另一个线程可以看到有趣的事情-对于那些需要使用C11原子功能或编译器扩展/保证的人。
答案 1 :(得分:1)
CPU可以重新排序两个存储,只要它不违反CPU必须提供的任何保证即可。编译器的工作是为CPU生成代码,这不允许编译器进行优化,从而导致所生成的代码违反C标准。换句话说,C编译器采用它承诺将根据C标准的规则运行的代码,并通过依赖于CPU将其转换为实际上将根据C标准的规则运行的汇编代码。按照其体系结构规范的规则运行。
因此,如果这两个存储恰好位于相同的内存位置,则不可能进行“优化”,从而无法从同一线程观察到错误的结果。这将违反C标准,因此,不间断的编译器将生成不间断的CPU不执行此操作所需的任何代码。但是,除非平台的线程标准说了一些不同(我所不知道的事情),否则没有什么能阻止可能导致其他线程看到奇怪的中间结果的优化。
如果要跨线程保证,则必须使用原子操作,互斥量或平台为此提供的任何其他功能。如果您只希望代码能够正常工作,则需要特定于平台的知识,以了解平台实际能够执行的优化以及在该平台上禁用它们的方法(volatile
,编译器标志等)