use*_*550 6 c assembly gcc compilation memory-barriers
试图继续我的想法,使用软件和硬件内存障碍,我可以禁用编译器优化编译的代码中的特定函数的无序优化,因此我可以使用像Peterson或等算法实现软件信号量Deker这不需要无序执行,我测试了以下包含SW barrier asm volatile("": : :"memory")和gcc builtin HW barrier的代码__sync_synchronize:
#include <stdio.h>
int main(int argc, char ** argv)
{
int x=0;
asm volatile("": : :"memory");
__sync_synchronize();
x=1;
asm volatile("": : :"memory");
__sync_synchronize();
x=2;
asm volatile("": : :"memory");
__sync_synchronize();
x=3;
printf("%d",x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但编译输出文件是:
main:
.LFB24:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
mfence
mfence
movl $3, %edx
movl $.LC0, %esi
movl $1, %edi
xorl %eax, %eax
mfence
call __printf_chk
xorl %eax, %eax
addq $8, %rsp
Run Code Online (Sandbox Code Playgroud)
如果我删除障碍并再次编译,我得到:
main
.LFB24:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $3, %edx
movl $.LC0, %esi
movl $1, %edi
xorl %eax, %eax
call __printf_chk
xorl %eax, %eax
addq $8, %rsp
Run Code Online (Sandbox Code Playgroud)
两者都gcc -Wall -O2在Ubuntu 14.04.1 LTS,x86中编译.
预期的结果是包含内存屏障的代码的输出文件将包含我在源代码中的值的所有赋值,以及mfence它们之间的值.
根据相关的StackOverflow帖子 -
gcc内存屏障__sync_synchronize vs asm volatile("":::"memory")
在每次迭代时添加内联汇编时,不允许gcc更改通过屏障的操作顺序
后来:
但是,当CPU执行此代码时,只要它不破坏内存排序模型,就允许对"引擎盖下"的操作进行重新排序.这意味着执行操作可以不按顺序进行(如果CPU支持这种操作,那么这些日子大多数都是这样做的).HW围栏会阻止它.
但正如您所看到的,代码与内存屏障和没有内存屏障的代码之间的唯一区别在于,前者包含mfence的方式是我不希望看到它,并且并非包含所有分配.
为什么带有内存屏障的文件的输出文件不像我预期的那样 - 为什么mfence订单被改变了?为什么编译器会删除一些赋值?即使应用了内存屏障,编译器是否允许进行此类优化并分离每一行代码?
引用内存屏障类型和用法:
内存屏障告诉编译器/CPU 指令不应跨屏障重新排序,它们并不意味着无论如何都必须执行可以证明毫无意义的写入。
如果你定义你的xas volatile,编译器就不能做出这样的假设:它是唯一关心xs 值的实体,并且必须遵循 C 抽象机的规则,这是为了内存写入实际发生。
在您的特定情况下,您可以跳过障碍,因为它已经保证易失性访问不会相互重新排序。
如果您有 C11 支持,那么最好使用_Atomics,这还可以保证正常分配不会根据您的重新排序x,并且访问是原子的。
编辑:GCC(以及 clang)在这方面似乎不一致,并且不会总是进行这种优化。我打开了有关此问题的 GCC 错误报告。
| 归档时间: |
|
| 查看次数: |
1587 次 |
| 最近记录: |