__asm__ __volatile__ (“” : : : “memory”)内存屏障

__asm__ __volatile__ (“” : : : “memory”)

该语句创建一个编译器层的存储屏障(memory barrier),告诉编译器不要越过该屏障优化存储器的访问顺序.举例来说,如果你要访问某地址需要特殊的顺序(可能因为那地址的数据是其它设备的返回值)就要告诉编译器不要优化你的访问顺序,防止编译器会考虑效率问题而优化你的读写顺序.

在这个例子中先让某地址的值加1,然后读数据,并且让另一个相邻地址的值加1,代码如下:

int c(int *d, int *e) {
        int r;
        d[0] += 1; // d[0]地址的值+1
        r = e[0];   // 读取e[0]地址的值
        d[1] += 1;// d[1]地址的值+1
        return r;
}

问题是编译器为了优化效率可能会重新排序生成以下汇编:

00000000 :
   0:   4603        mov r3, r0 			;r0 -> r3
   2:   c805        ldmia   r0, {r0, r2}		;读取r0地址开始的两个数据到r0,r2
   4:   3001        adds    r0, #1			;r0=r0+1
   6:   3201        adds    r2, #1			;r2=r2+1
   8:   6018        str r0, [r3, #0]			;写回r0的值
   a:   6808        ldr r0, [r1, #0]			;读取r1地址的值到r0
   c:   605a        str r2, [r3, #4]			;写回r2的值
   e:   4770        bx  lr

上面代码d[0],d[1]的值是同时读取的,如果你想避免这样,你需要告诉编译不要优化读取内存的顺序,就要用到

__asm__ __volatile__ (“” : : : “memory”)

代码如下:

int c(int *d, int *e) {
        int r;
        d[0] += 1; // d[0]地址的值+1
        r = e[0];   // 读取e[0]地址的值
        __asm__ __volatile__ (“” : : : “memory”);
        d[1] += 1;// d[1]地址的值+1
        return r;
}

这样才能得到需要的访问顺序:

00000000 :
   0:   6802        ldr r2, [r0, #0]	;加载r0地址的值到r2
   2:   4603        mov r3, r0	;r0->r3
   4:   3201        adds    r2, #1	;r2=r2+1
   6:   6002        str r2, [r0, #0]	;写回r0地址
   8:   6808        ldr r0, [r1, #0]	;加载r1地址的值到r0
   a:   685a        ldr r2, [r3, #4]	;加载r0+4地址的值到r2
   c:   3201        adds    r2, #1	;r2=r2+1
   e:   605a        str r2, [r3, #4] 	;写回r0+4地址
  10:   4770        bx  lr
  12:   bf00        nop

注意,这样做只是在编译的时候加入内存屏障来避免编译器重新排序内存访问,并没有加入额外的指令来刷新内存或等待读写完成.

参考关于__asm__ volatile (“” : : : “memory”)

你可能感兴趣的:(__asm__ __volatile__ (“” : : : “memory”)内存屏障)