
- Volatile 与 内存屏障 与 CPU重排序
(1) volatile 只能保证编译器不会做乱序执行优化,无法保证CPU执行时不乱序执行。
(2) 要保证CPU执行时不乱序执行,需要内存屏障(memory barrier),形式如下:
_asm_ _volatile_("":::"memory") 其中的组成详解如下:
_asm_ 用于指示编译器在此插入汇编语句;
_volatile_ 等同于c语言的volatile
::: 表示这个是空指令。
memory 强制gcc编译器假RAM所有的内存单元均被汇编指令修改,这样CPU中的registers 和cache中以缓存的内存单元中的数据将作废。CPU将不得不在需要的时候重新读取内存中的数据,这样就阻止了又将registers,cache中的数据用于优化指令而比曼去访问内存!!
对于内存屏障封装最常见的宏为: xxx_mb(), barrier() 等:
mb() 适用于多处理器和单处理器的内存屏障
rmb() 适用于多处理器和单处理器的读内存屏障
wmb() 适用于多处理器和单处理器的写内存屏障
smp_ mb() 适用于多处理器的内存屏障
smp_rmb() 适用于多处理器的读内存屏障
smp_wmb() 适用于多处理器的写内存屏障.
前提:读可以多线程,写必须单线程,如果是多线程写,则做不到无锁。 内存屏障的核心是:一写多读,完全无锁,对于多线程写的情况,内存屏障完全无用。 在多核CPU中,改过的值可能还在当前CPU的缓存中,没有刷新到内存中,内核屏障就是要强制把这个值刷新到内存中。
(3) CPU指令重排:多核的CPU中才会出现!!! 指令重排 无法逾越 内存屏障
为什么CPU 与 内存之间会有缓存 :程序中CPU计算 与 内存交互,CPU计算速度 远远高于 与内存交互的速度,所以为了提高速度而引入了缓存,缓存一致性是保证数据准确性的基础。在多处理器时,单个CPU对缓存的改动,需要通知其他CPU,所以CPU不仅要控制自己的读写操作,还要监听其他CPU发出的通知,从而保证数据的最终一致性!!
CPU性能优化手段----运行时指令重排:
当CPU写缓存时发现缓存被其他CPU占用,为了提高CPU性能,遵循as-if-serial语义 可将后面的读缓存命令优先执行。其中as-if-serial语义:不管怎么重排,(单线程)程序的执行结果不能改变。
CPU高速缓存下出现的问题:
缓存中的数据和主内存的数据并不是实时同步的,各个CPU间的缓存数据也不是实时同步的,在同一时间内存地址的数据值可能不一致。 解决方案:读内存屏障。
CPU重排出现的问题:
多核多线程中,指令逻辑无法分辨因果关系,可能出现乱序执行,导致程序运行结果出错。 解决方案:写内存屏障。
网友评论