__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”)