2016-08-03 36 views
6

试图用我的想法去上同时使用软件和硬件的记忆障碍,我可以禁用外,为了优化为与编译器的优化编译代码内部的特定功能的,因此我也使用像PetersonDeker算法需要外的顺序没有执行实现软件旗语,我已经测试了以下代码包含两个SW屏障asm volatile("": : :"memory")和gcc内建HW屏障__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; 
} 

但是,编译输出文件是:

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 

如果我消除障碍并重新编译,我得到:

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 

都在Ubuntu 14.04.1 LTS,86与gcc -Wall -O2编译。

预期的结果是,包含内存障碍的代码的输出文件将包含我在源代码中的值的所有赋值,其中包含mfence

根据相关的StackOverflow职位 -

gcc memory barrier __sync_synchronize vs asm volatile("": : :"memory")

当在每次迭代增加你的内联汇编,GCC不允许改变操作的顺序,经过阻挡

及以后:

Howe版本,当CPU performes这个代码,它允许重新排序 操作“引擎盖下”,只要它不会破坏内存 排序模型。这意味着执行操作可能不按顺序完成(如果CPU支持该操作,就像现在大多数操作一样)。 HW 围栏会阻止这种情况发生。

但正如你所看到的,与记忆障碍的代码,并没有他们的代码之间的唯一区别在于,前者包含了一个办法,我不希望看到它mfence,而不是所有的任务被包含在内。

为什么与记忆障碍的文件的输出文件并没有如我expected-为什么mfence顺序已经被改变?为什么编译器删除了一些任务?是否允许编译器进行优化,即使应用了内存屏障并将每行代码分开了?

引用到存储器屏障类型和使用:

+1

术语:**乱序执行独立于内存重新排序**。即使按顺序的CPU也是流水线式的,并且受益于存储缓冲区,特别是对于L1中错过的商店。 (https://en.wikipedia.org/wiki/MESI_protocol#Memory_Barriers。一旦它们被认为不是推测性的,只有通过内存排序逻辑才能对它们进行跟踪(如果需要,可以强制执行StoreStore和LoadStore排序),直到它们实际上在管道忘记它们之后提交到​​L1缓存。)'MFENCE'不会序列化流水线;它仅序列化内存操作变为全局可见的顺序。 –

回答

4

存储器障碍告诉编译器/ CPU该指令不应该跨越障碍重新排序,它们并不意味着无论如何都可以证明无效的写入。

如果你定义xvolatile,编译器不能作一个假设,即它是在乎x价值并具有遵循C抽象的机器,这对于存储器写入规则的唯一实体实际发生。

在你的具体情况下,你可以跳过障碍,因为它已经保证了易失性访问不会相互重排。

如果您有C11支持,您最好使用_Atomic,它还可以保证不会针对您的x重新排序正常分配,并且访问是原子性的。


编辑:GCC(以及铛),似乎在这方面的不一致,也不会总是这样做optimizaton。 I opened a GCC bug report regarding this.

+3

你写了比我好得多的答案。 – 2501

+0

正确的答案。我已经用'volatile'测试了它,并且带有内存屏障的代码按照我的预期进行了编译(而没有内存屏障的代码仍然进行了优化)。不幸的是,我不能测试'atomic',因为我没有C11的支持。 – user2162550

+0

@ 2501谢谢。如果您认为可以改进,请随意扩展它。 :) – a3f