缓存一致性
在多处理器系统中,每个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 |
|