备注:OSG  OpenThread::Atomic.cpp中MemoryBarrier();

Atomic::operator unsigned() const
{
#if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)__sync_synchronize();return _value;
#elif defined(_OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED)MemoryBarrier();return _value;
#elif defined(_OPENTHREADS_ATOMIC_USE_BSD_ATOMIC)OSMemoryBarrier();return static_cast<unsigned const volatile>(_value);
#else
# error This implementation should happen inline in the include file
#endif
}

MemoryBarrier();保证函数返回的值,直接从内存中读取,而不是从寄存器中读取;


内核中定义的内存屏障原语有:

#define barrier() __asm__ __volatile__("": : :"memory") #define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2) #define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2) #ifdef CONFIG_SMP #define smp_mb() mb() #define smp_rmb() rmb() #define smp_wmb() wmb() #define smp_read_barrier_depends() read_barrier_depends() #define set_mb(var, value) do { (void) xchg(&var, value); } while (0) #else #define smp_mb() barrier() #define smp_rmb() barrier() #define smp_wmb() barrier() #define smp_read_barrier_depends() do { } while(0) #define set_mb(var, value) do { var = value; barrier(); } while (0) #endif 1). smp_xxx()和xxx()的差别 为了给其他CPU也提供相关的barrier宏。 比如x86的rmb()是用了lfence指令,但其他CPU不能用这个指令。 2). 关于barrier()宏,jkl大师是这么说的: CPU越过内存屏障后,将刷新自己对存储器的缓冲状态。这条语句实际上不生成不论什么代码,但可使gcc在 barrier()之后刷新寄存器对变量的分配。 也就是说,barrier()宏仅仅约束gcc编译器,不约束执行时的CPU行为。 举例: 1 int a = 5, b = 6; 2 barrier(); 3 a = b; 在line 3,GCC不会用存放b的寄存器给a赋值,而是invalidate b的Cache line,又一次读内存中的b值,赋值给a。 3). mb() vs. rmb() vs. wmb() rmb()不同意读操作穿过内存屏障;wmb()不同意写操作穿过屏障;而mb()二者都不同意。 看IA32上wmb()的定义: #ifdef CONFIG_X86_OOSTORE #define wmb() alternative("lock;addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM); #else #define wmb() __asm__ __volatile__ ("": : :"memory"); #endif Intel和AMD都没有在IA32 CPU中实现乱序写(Out-Of-Order Store),所以wmb()定义为空操作,不约束CPU行为;但 有些IA32 CPU厂商实现了OOO Store,所以就有了使用sfence的那个wmb()实现。

总线加锁的功能是保证程序运行的顺序不乱掉, 一旦加LOCK指令了,CPU会将此指令前的读写操作都串行完毕,这最基本的作用是使CPU的预取等无效了。 在这个串行操作中,MESI协议会起作用。 但保证全部CPU的Cache一致性的是MESI协议,这是硬件上保证的。 barrier是对GCC编译器做约束,是软件层次上的。 “因此barrier就能保证全部CPU的Cache一致性”这样的说法是不正确的。 lock指令保证程序运行的顺序不乱掉,没有将“本CPU的Cache写入了内存”的功能。 总线监视功能是由各个CPU的CACHE完毕的, 这个功能能够算是MESI协议的实现。MESI保证了SMP下的CACHE一致性。 

MESI协议

包含IA32的很多体系结构的CPU,为了保证缓存一致性,实现了MESI协议。

M: Modified,已改动 
E: Exclusive,排他 
S: Shared,共享 
I: Invalid,无效

IA32 的CPU实现了MESI协议来保证Cache coherence。 CPU的总线监測单元,始终监视着总线上全部的内存写操作, 
以便随时调整自己的Cache状态。

-> Modified。 本CPU写,则直接写到Cache,不产生总线事物;其他CPU写,则不涉及本CPU的Cache,其他CPU 
读,则本CPU须要把Cache line中的数据提供给它,而不是让它去读内存。

-> Exclusive。仅仅有本CPU有该内存的Cache,并且和内存一致。 本CPU的写操作会导致转到Modified状态。

-> Shared。 多个CPU都对该内存有Cache,并且内容一致。不论什么一个CPU写自己的这个Cache都必须通知其他 
的CPU。

-> Invalid。 一旦Cache line进入这个状态,CPU读数据就必须发出总线事物,从内存读。

5) 考虑到DMA

5.1). Wirte through策略。 这样的情形比較简单。

-> 本CPU写内存,是write through的,因此不管什么时候DMA读内存,读到的都是正确数据。 
-> DMA写内存,假设DMA要写的内存被本CPU缓存了,那么必须Invalidate这个Cache line。下次CPU读它,就 
直接从内存读。

5.2). Write back策略。 这样的情形相当复杂。

-> DMA读内存。被本CPU总线监视单元发现,并且本地Cache中有Modified数据,本CPU就截获DMA的内存读操作, 
把自己Cache Line中的数据返回给它。

-> DMA写内存。并且所写的位置在本CPU的Cache中,这又分两种情况: 
a@ Cache Line状态未被CPU改动过(即cache和内存一致),那么invalidate该cache line。 
b@ Cache Line状态已经被改动过,又分2种情况:

<1> DMA写操作会替换CPU Cache line所相应的整行内存数据,那么DMA写,CPU则invalidate 
自己的Cache Line。 
<2> DMA写操作仅仅替换Cache Line相应的内存数据的一部分,那么CPU必须捕获DMA写操作的新 
数据(即DMA想把它写入内存的),用来更新Cache Line的相关部分。

转载于:https://www.cnblogs.com/zfyouxi/p/4022822.html

关于MemoryBarrier相关推荐

  1. 【转】细说.NET中的多线程 (六 使用MemoryBarrier,Volatile进行同步)

    上一节介绍了使用信号量进行同步,本节主要介绍一些非阻塞同步的方法.本节主要介绍MemoryBarrier,volatile,Interlocked. MemoryBarriers 本文简单的介绍一下这 ...

  2. Lock,LockFree,MemoryBarrier,ConcurrentCollection

    最近看并行编程书本的一些心得,简单记录下多线程和并行编程必知必会的几个概念,再次加深自己的理解. .NET Framework4提供了一个新的命名空间System.Collections.Concur ...

  3. Java线上问题排障:Linux内核bug引发JVM死锁导致线程假死

    Java本质上还是离不开操作系统,一来Java源码是用C/C++实现的,二来java进程还是需要依附于操作系统和硬件资源,有时候一些问题是操作系统级别导致的,下面的整个事件是源自一则真实的线上案例. ...

  4. 并发编程专题——第一章(深入理解java内存模型)

    说到并发编程,其实有时候觉得,开发中真遇到这些所谓的并发编程,场景多吗,这应该是很多互联网的在职人员,一直在考虑的事情,也一直很想问,但是又不敢问,想学习的同时,网上这些讲的又是乱七八糟,那么本章开始 ...

  5. 对volatile的理解

    JMM 是什么 JMM(java内存模型 Java Memory Model)本身是一种抽象的概念,描述一组规则后规范通过这组规范定义了程序中各个变量(包括实例字段,静态变量和组成数组对象的元素)的访 ...

  6. Cygwin编译cef

    1.下载cygwin,并安装如下项: autobuild autoconf autogen automake ccrypt cmakegcc-g++gdb httpd libGLw-devel lib ...

  7. Singleton、MultiThread、Lib——实现单实例无锁多线程安全API

        前阵子写静态lib导出单实例多线程安全API时,出现了CRITICAL_SECTION初始化太晚的问题,之后查看了错误的资料,引导向了错误的理解,以至于今天凌晨看到另一份代码,也不多想的以为s ...

  8. 《为什么在多核处理器下需要内存屏障(MenmoryBarrier)?》

    <为什么在多核处理器下需要内存屏障(MenmoryBarrier)?> 因为CPU的乱序执行技术虽然可以极大的提高流水线的工作效率,但是导致了实际运行次序和program的次序不一致,如果 ...

  9. 有关“双重检查锁定失效”的说明

    双重检查锁定(以下称为DCL)已被广泛当做多线程环境下延迟初始化的一种高效手段. 遗憾的是,在Java中,如果没有额外的同步,它并不可靠.在其它语言中,如c++,实现DCL,需要依赖于处理器的内存模型 ...

  10. CLR Via C# 3rd 阅读摘要 -- Chapter 28 – Primitive Thread Synchronization Constructs

    Class Libraries and Thread Safety 线程同步是用来避免多个线程同时访问共享数据时出现冲突: 线程同步的障碍: 1.极其乏味易错: 2.锁严重影响性能: 3.线程同步锁在 ...

最新文章

  1. javascript等号判断相等流程
  2. Oracle-洛总脚本--查询相关慢SQL
  3. BIOS详情设置续一
  4. MaxCompute平台非标准日期和气象数据处理方法--以电力AI赛为例
  5. GNU/Linux下的开发环境
  6. XP系统还原计算机用户名,详细教你xp系统还原操作方法
  7. HSqlDB(java内置数据库)
  8. 搭建阿里云服务器内有阿里云幸运券
  9. 忘记背后 努力面前 向着标杆直跑!(转)
  10. Multithreading and Synchronization
  11. P1002 [NOIP2002 普及组] 过河卒
  12. 傲气雄鹰android 3dm,傲气雄鹰 重载
  13. 惊了!原来 Web 发展历史是这样的
  14. 打印机打印服务自动关闭与无法启动问题
  15. 基于逻辑回归算法的心脏病不平衡数据分类代码实现
  16. 魔兽世界服务器维护12月13日,3月27日服务器维护提前完成 更新12M工具补丁
  17. 1103平均分绩点(函数专题)
  18. 眼界决定境界,格局决定结局
  19. 思维导图 || 统计学习三要素
  20. 2011年腾讯实习生应聘(软件开发Web前端flash方向)笔试面试经历

热门文章

  1. Linux 查看日志命令
  2. 教案设计计算机,计算机应用基础教案设计
  3. 电压转电流模块电路设计原理解析
  4. voms下的反射大师_VOMS虚拟大师
  5. 编程常用资料/网站收集
  6. 虚拟机使用主机摄像头 ” usb chicony lenovo easycamera 连接失败,驱动错误“
  7. linux服务器发异常包,如何排查Linux服务器上的恶意发包行为
  8. 3D优化之ShadowGun系列三:shader系列汇总
  9. 商家如何制作外卖小程序并且对接同城外卖配送平台?
  10. HP5100常见错误代码