Sou*_*a B 1 c++ assembly arm volatile memory-barriers
根据 cppreference,一个volatile限定变量的存储不能重新排序为另一个volatile限定变量。换句话说,在下面的示例中,当 y 变为 20 时,可以保证 x 为 10。
volatile int x, y;
...
x = 10;
y = 20;
Run Code Online (Sandbox Code Playgroud)
根据维基百科,ARM 处理器的一个存储可以在另一个存储之后重新排序。因此,在下面的示例中,第二个存储可以在第一个存储之前执行,因为两个目的地是不相交的,因此它们可以自由地重新排序。
str r1, [r3]
str r2, [r3, #4]
Run Code Online (Sandbox Code Playgroud)
有了这样的理解,我写了一个玩具程序:
volatile int x, y;
int main() {
x = 10;
y = 20;
}
Run Code Online (Sandbox Code Playgroud)
我预计生成的程序集中会出现一些围栏,以保证 x 和 y 的存储顺序。但为 ARM生成的程序集是:
main:
movw r3, #:lower16:.LANCHOR0
movt r3, #:upper16:.LANCHOR0
movs r1, #10
movs r2, #20
movs r0, #0
str r1, [r3]
str r2, [r3, #4]
bx lr
x:
y:
Run Code Online (Sandbox Code Playgroud)
那么,这里如何强制存储顺序呢?
因此,在下面的示例中,第二个存储可以在第一个存储之前执行,因为两个目的地是不相交的,因此它们可以自由地重新排序。
该volatile关键字限制编译器对指令的重新排序(和省略),但其语义没有说明其他线程或处理器的可见性。
当你看到
str r1, [r3]
str r2, [r3, #4]
Run Code Online (Sandbox Code Playgroud)
然后volatile已完成所需的一切。x如果和的地址y是 I/O 映射到硬件设备,则它将x首先接收到存储。如果中断在两条指令之间暂停该线程的操作,则中断处理程序将看到存储x而不是y. 这就是所有的保证。
内存排序模型仅描述从其他处理器可观察到的效果的顺序。它不会改变指令发出的顺序(即它们在汇编代码中出现的顺序),而是改变它们提交的顺序(即,存储变得外部可见)。
y当然有可能不同的处理器可以在之前看到存储的结果x- 但volatile不是也从来没有与该问题相关。对此的跨平台解决方案是std::atomic.
不幸的是,互联网上有大量过时的 C 代码可用于同步volatile- 但这始终是特定于平台的扩展,无论如何都不是一个好主意。更不幸的是,该关键字在 Java 中被赋予了完全相同的语义(它并不真正用于编写中断处理程序),这增加了混乱。
如果您确实看到volatile类似这样的东西,那么它要么已经过时,要么是从 Java 翻译而来的。使用std::atomic,对于比简单原子加载/存储更复杂的任何事情,使用 可能更好(而且当然更容易)std::mutex。
| 归档时间: |
|
| 查看次数: |
587 次 |
| 最近记录: |