cpu 会将 STORE 指令重新排序到同一地址吗?
will cpu reorder STORE instructions to same address?
给出下面的代码,CPU 会重新排序 STORE a 和 STORE b 吗?从代码逻辑上看,a和b是独立的。
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;
}
你现在的问题几乎毫无意义。
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 原子特性,或者编译器 extension/guarantee.
只要不违反CPU必须提供的任何保证,CPU可以重新订购这两家商店。编译器的工作是为 CPU 生成代码,不允许它进行优化,导致生成的代码违反 C 标准。换句话说,C 编译器采用它承诺将 运行 根据 C 标准规则的代码,并将其转换为汇编代码,实际上根据 C 标准的规则 运行 C标准依托于CPU到运行根据其架构规范的规则。
因此,如果这两个存储碰巧位于同一内存位置,则 "optimization" 不可能允许从同一个线程观察到错误结果。这将违反 C 标准,因此未损坏的编译器将生成未损坏的 CPU 不执行此操作所需的任何代码。但是,没有什么可以阻止可能导致其他线程看到奇怪的中间结果的优化,除非你的平台的线程标准说的是不同的东西(而且 none 我知道这样做)。
如果你想要跨线程保证,你必须使用原子操作、互斥锁或你的平台为此提供的任何其他东西。如果您只是想要恰好可以工作的代码,您将需要特定于平台的知识,了解您的平台实际能够进行哪些优化以及在该平台上有哪些方法可以禁用它们(volatile
、编译器标志等) .
给出下面的代码,CPU 会重新排序 STORE a 和 STORE b 吗?从代码逻辑上看,a和b是独立的。
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;
}
你现在的问题几乎毫无意义。
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 原子特性,或者编译器 extension/guarantee.
只要不违反CPU必须提供的任何保证,CPU可以重新订购这两家商店。编译器的工作是为 CPU 生成代码,不允许它进行优化,导致生成的代码违反 C 标准。换句话说,C 编译器采用它承诺将 运行 根据 C 标准规则的代码,并将其转换为汇编代码,实际上根据 C 标准的规则 运行 C标准依托于CPU到运行根据其架构规范的规则。
因此,如果这两个存储碰巧位于同一内存位置,则 "optimization" 不可能允许从同一个线程观察到错误结果。这将违反 C 标准,因此未损坏的编译器将生成未损坏的 CPU 不执行此操作所需的任何代码。但是,没有什么可以阻止可能导致其他线程看到奇怪的中间结果的优化,除非你的平台的线程标准说的是不同的东西(而且 none 我知道这样做)。
如果你想要跨线程保证,你必须使用原子操作、互斥锁或你的平台为此提供的任何其他东西。如果您只是想要恰好可以工作的代码,您将需要特定于平台的知识,了解您的平台实际能够进行哪些优化以及在该平台上有哪些方法可以禁用它们(volatile
、编译器标志等) .