为什么可以相对于非易失性访问对这种易失性访问进行重新排序?
Why can this volatile access be reordered with respect to a non-volatile access?
下面的代码示例来自Chinese blog,其中介绍了volatile
的效果。左边是C代码;另一个是生成的汇编代码。
// cordering.c gcc -O2 -S -masm=intel cordering.c
int A;
volatile int B;
void foo() mov eax, DWORD PTR B[rip]
{ mov DWORD PTR B[rip], 0
A = B + 1; add eax, 1
B = 0; mov DWORD PTR A[rip], eax
} ret
正如我们在汇编代码中看到的,A
的副作用放在 B
的副作用之后,即使 B
是 volatile
合格的。但是,cppreference.com says:
[W]ithin a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access.
这里A
的副作用排在B
之前,所以我认为编译器这样做是不合法的。我说得对吗?
作为补充,博客说如果我们要保证volatile
和non-volatile
类型之间的顺序,我们需要同时使volatile
:
// cordering.c gcc -O2 -S -masm=intel cordering.c
volatile int A;
volatile int B;
void foo() mov eax, DWORD PTR B[rip]
{ add eax, 1
A = B + 1; mov DWORD PTR A[rip], eax
B = 0; mov DWORD PTR B[rip], 0
} ret
您链接的页面显示:
Every access (read or write operation, member function call, etc.)
made through a glvalue expression of volatile-qualified type is
treated as a visible side-effect for the purposes of optimization
(that is, within a single thread of execution, volatile accesses
cannot be optimized out or reordered with another visible side effect
that is sequenced-before or sequenced-after the volatile access.
因此,如果 A
不是 volatile
,对 A
的访问不会被视为可见的副作用,并且第二个语句不适用(因为它不不要说任何关于重新排序可见和不可见访问的事情。
编辑:
请注意,cppreference 不是 C++ 的官方文档,而是社区的成果。我确实相信粗体声明的目的是定义什么是可见的副作用,但没有写清楚。
最终参考是 C++ 标准(here 是获取它的一些选项)。
N4659 标准草案在 [intro.execution] 第 14 段和 [=32= 中定义了 副作用 ]可见的副作用 通过 [intro.races] 中的 2 页定义链。
我不是 C++ 标准的专家,所以我无法不费吹灰之力就理解标准的确切内容,但欢迎您尝试一下。
但是,对于允许编译器进行哪些优化的非正式解释,您可以查看 cppreference 上的 as-if rule。
编辑 2:该标准还在 [intro.execution] 中正式指定了 as-if 规则 ,第 7 段:
The least requirements on a conforming implementation are:
(7.1) — Accesses through volatile glvalues are evaluated strictly according to
the rules of the abstract machine.
(7.2) — At program termination, all
data written into files shall be identical to one of the possible
results that execution of the program according to the abstract
semantics would have produced.
(7.3) — The input and output dynamics
of interactive devices shall take place in such a fashion that
prompting output is actually delivered before a program waits for
input. What constitutes an interactive device is
implementation-defined.
简而言之,任何优化都是有效的,只要程序产生相同的输出,并且对 volatile 对象的读取和写入以正确的顺序发生,这适用于您的原始示例。
下面的代码示例来自Chinese blog,其中介绍了volatile
的效果。左边是C代码;另一个是生成的汇编代码。
// cordering.c gcc -O2 -S -masm=intel cordering.c
int A;
volatile int B;
void foo() mov eax, DWORD PTR B[rip]
{ mov DWORD PTR B[rip], 0
A = B + 1; add eax, 1
B = 0; mov DWORD PTR A[rip], eax
} ret
正如我们在汇编代码中看到的,A
的副作用放在 B
的副作用之后,即使 B
是 volatile
合格的。但是,cppreference.com says:
[W]ithin a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access.
这里A
的副作用排在B
之前,所以我认为编译器这样做是不合法的。我说得对吗?
作为补充,博客说如果我们要保证volatile
和non-volatile
类型之间的顺序,我们需要同时使volatile
:
// cordering.c gcc -O2 -S -masm=intel cordering.c
volatile int A;
volatile int B;
void foo() mov eax, DWORD PTR B[rip]
{ add eax, 1
A = B + 1; mov DWORD PTR A[rip], eax
B = 0; mov DWORD PTR B[rip], 0
} ret
您链接的页面显示:
Every access (read or write operation, member function call, etc.) made through a glvalue expression of volatile-qualified type is treated as a visible side-effect for the purposes of optimization (that is, within a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access.
因此,如果 A
不是 volatile
,对 A
的访问不会被视为可见的副作用,并且第二个语句不适用(因为它不不要说任何关于重新排序可见和不可见访问的事情。
编辑: 请注意,cppreference 不是 C++ 的官方文档,而是社区的成果。我确实相信粗体声明的目的是定义什么是可见的副作用,但没有写清楚。
最终参考是 C++ 标准(here 是获取它的一些选项)。 N4659 标准草案在 [intro.execution] 第 14 段和 [=32= 中定义了 副作用 ]可见的副作用 通过 [intro.races] 中的 2 页定义链。 我不是 C++ 标准的专家,所以我无法不费吹灰之力就理解标准的确切内容,但欢迎您尝试一下。
但是,对于允许编译器进行哪些优化的非正式解释,您可以查看 cppreference 上的 as-if rule。
编辑 2:该标准还在 [intro.execution] 中正式指定了 as-if 规则 ,第 7 段:
The least requirements on a conforming implementation are:
(7.1) — Accesses through volatile glvalues are evaluated strictly according to the rules of the abstract machine.
(7.2) — At program termination, all data written into files shall be identical to one of the possible results that execution of the program according to the abstract semantics would have produced.
(7.3) — The input and output dynamics of interactive devices shall take place in such a fashion that prompting output is actually delivered before a program waits for input. What constitutes an interactive device is implementation-defined.
简而言之,任何优化都是有效的,只要程序产生相同的输出,并且对 volatile 对象的读取和写入以正确的顺序发生,这适用于您的原始示例。