A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© z1595390120 初级黑马   /  2019-5-31 15:16  /  791 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

缓存一致性

在多处理器系统中,每个cpu都有自己的缓存,它们都有一个共享的内存。内存和缓存中的数据要保持一致,通过一个协议MESI,是由硬件来完成缓存一致性的。一个cpu总能读到最新的数据,不管它是在自己的cache中,还是在其他cpu的cache中,还是在内存中,这就是缓存一致性。

我看很多资料上都写volatile可以保证缓存一致性,写时写到缓存,同时写到内存,读时直接读内存。我觉得它这么做不是为了保证,一个线程的修改对别的线程可见,因为这个可见性硬件可以保证(我目前觉得),而是为了告诉编译器,不要对我进行优化。如下面的代码:

int i;
i = 1;
i = 2

如果编译器优化的话,可能第一个赋值语句i=1就没有了,单从一个线程来看,有没有i=1这个赋值语句,都没有差别。但如果是多个线程同时执行的话,可能会对别的线程由影响,加上volatile就不会省略掉第一个赋值语句了,会严格按照程序编写编译。

顺序一致性

程序可能会被重排序,重排序会体现在两个地方:编译器和cpu。
在不影响单个线程执行结果的情况下,编译器可能会重新排列执行的顺序;cpu因为指令流水技术,互不影响的指令,可能会被发送到不同的流水线上,哪个先执行完就不一定了,这就间接形成了重排序。

变量设置了volatile关键字,会防止这两种重排序。

(下面是我目前的理解,不一定正确)
volatile最终是通过内存栅栏(也就是下面的内联汇编)防止重排序。

编译时内存栅栏实现:

__asm__ __volatile__("" ::: "memory")

它会防止编译时指令重排,但不会防止执行时cpu重排。

__asm__ __volatile__("mfence" ::: "memory");
__asm__ __volatile__("lfence" ::: "memory");

硬件内存栅栏实现:
不同系统实现不同,下面是x86,x86-64

lfence (asm), void _mm_lfence(void)
sfence (asm), void _mm_sfence(void)[10]
mfence (asm), void _mm_mfence(void)[

编译器对硬件内存栅栏的支持:

GCC,[13] version 4.4.0 and later,[14] has __sync_synchronize.
Since C11 and C++11 an atomic_thread_fence() command was added.
The Microsoft Visual C++ compiler[15] has MemoryBarrier().
Sun Studio Compiler Suite[16] has __machine_r_barrier, __machine_w_barrier and __machine_rw_barrier.
unofficial open jdk – github
openjdk8 源码下载

这个类里面有内存屏障的代码,针对不同的平台有不同的实现:
openjdk/src/hotspot/os_cpu/xxx/orderAccess_xxx.hpp

// A compiler barrier, forcing the C++ compiler to invalidate all memory assumptions
inline void compiler_barrier() {
  __asm__ volatile ("" : : : "memory");
}

inline void OrderAccess::loadload() { compiler_barrier(); }
inline void OrderAccess::storestore() { compiler_barrier(); }
inline void OrderAccess::loadstore() { compiler_barrier(); }
inline void OrderAccess::storeload() { fence(); }

inline void OrderAccess::acquire() { compiler_barrier(); }
inline void OrderAccess::release() { compiler_barrier(); }

inline void OrderAccess::fence() {
#ifdef AMD64
  __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory");
#else
  __asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");
#endif
  compiler_barrier();
}

#endif // OS_CPU_SOLARIS_X86_VM_ORDERACCESS_SOLARIS_X86_HPP

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马