指令重排序
程序在运行时内存实际的访问顺序和程序代码编写的访问顺序不一定一致,这就是内存乱序访问。内存乱序访问行为出现的理由是为了提升程序运行时的性能。这种内存乱序问题主要是由两种原因引起的:
-
1.
写内存屏障(Store Memory Barrier)
: 在指令后插入Store Barrier, 能让写入缓存中的最新数据更新写入主内存, 让其他线程可见强制写入主内存, 这种显示调用, CPU就不会因为性能考虑而进行指令重排。 -
2.
读内存屏障(Load Memory Barrier)
: 在指令前插入Load Barrier, 可以让高速缓存中的数据失效, 强制从新从主内存读取数据强制读取主内存内容, 让CPU缓存和主内存保持一致, 避免了缓存导致的一致性问题。
什么是内存屏障
内存屏障(Memory Barrier)与内存栅栏(Memory Fence)是同一个概念,不同的叫法。
内存屏障(memory barrier)
是一个CPU指令。该指令可以确保一些特定操作执行的顺序 影响一些数据的可见性(可能是某些指令执行后的结果)。为了禁止编译器和CPU对代码进行重排序,在编译器和CPU层面上都有对应的指令。
作用
-
强制cpu将store buffer中的内容写入到cacheline中
-
强制cpu将invalidate queue中的请求处理完毕
类型 -
内存屏障是为了解决在cacheline上的操作重排序问题。
- 编译器在编译时进行了编译优化,导致指令重排;
- 在多cpu环境下,为了尽可能地避免处理器访问主内存的时间开销,处理器大多会利用缓存(cache)以提高性能。在这种模型下会存在一个现象,即缓存中的数据与主内存的数据并不是实时同步的,各CPU(或CPU核心)间缓存的数据也不是实时同步的。这导致在同一个时间点,各CPU所看到同一内存地址的数据的值可能是不一致的。从程序的视角来看,就是在同一个时间点,各个线程所看到的共享变量的值可能是不一致的。
内存屏障可以被分为以下几种类型
Store:将处理器缓存的数据刷新到内存中。
Load:将内存存储的数据拷贝到处理器的缓存中。
- LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取