关于MemoryBarrier
备注: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的相关部分。
关于MemoryBarrier的更多相关文章
- Lock,LockFree,MemoryBarrier,ConcurrentCollection
最近看并行编程书本的一些心得,简单记录下多线程和并行编程必知必会的几个概念,再次加深自己的理解. .NET Framework4提供了一个新的命名空间System.Collections.Concur ...
- 细说.NET中的多线程 (六 使用MemoryBarrier,Volatile进行同步)
上一节介绍了使用信号量进行同步,本节主要介绍一些非阻塞同步的方法.本节主要介绍MemoryBarrier,volatile,Interlocked. MemoryBarriers 本文简单的介绍一下这 ...
- MemoryBarrier,Volatile
使用MemoryBarrier,Volatile进行同步 上一节介绍了使用信号量进行同步,本节主要介绍一些非阻塞同步的方法.本节主要介绍MemoryBarrier,volatile,Interlock ...
- 【C# 线程】内存屏障 MemoryBarrier
背景 同步基元分为用户模式和内核模式 用户模式:Iterlocked.Exchange(互锁).SpinLocked(自旋锁).易变构造(volatile关键字.volatile类.Thread.Vo ...
- [百度空间] [转]内存屏障 - MemoryBarrier
处理器的乱序和并发执行 目前的高级处理器,为了提高内部逻辑元件的利用率以提高运行速度,通常会采用多指令发射.乱序执行等各种措施.现在普遍使用的一些超标量处理器通常能够在一个指令周期内并发执行多条指令. ...
- C#与C++的发展历程第三 - C#5.0异步编程巅峰
系列文章目录 1. C#与C++的发展历程第一 - 由C#3.0起 2. C#与C++的发展历程第二 - C#4.0再接再厉 3. C#与C++的发展历程第三 - C#5.0异步编程的巅峰 C#5.0 ...
- 《Note --- Unreal --- MemPro (CONTINUE... ...)》
Mem pro 是一个主要集成内存泄露检测的工具,其具有自身的源码和GUI,在GUI中利用"Launch" button进行加载自己待检测的application,目前支持的平台为 ...
- AliSQL的编译使用
1.下载源码 git clone https://github.com/alibaba/AliSQL.git Linux下编译 2.编译 编译前需要安装好gcc cmake bison等.(如果缺少其 ...
- Disruptor-NET和内存栅栏
Disruptor-NET算法(是一种无锁算法)需要我们自己实现某一种特定的内存操作的语义以保证算法的正确性.这时我们就需要显式的使用一些指令来控制内存操作指令的顺序以及其可见性定义.这种指令称为内存 ...
随机推荐
- [RxJS] Wrap up
Last thing to do is clean the score box and input, also auto foucs on input when click start. const ...
- JavaScripts学习日记——ECMAscript
1.Function对象 Function是一个很特殊的对象,特殊在该对象就像java中的方法一样,可以运行,可以传参数. 三种定义function对象的方法: 1.function fun1(a,b ...
- Java中日期时间API小结
Java中为处理日期和时间提供了大量的API,确实有把一件简单的事情搞复杂的嫌疑,各种类:Date Time Timestamp Calendar...,但是如果能够看到时间处理的本质就可以轻松hol ...
- 命令行下如何安装VMware Tools并与windows资料共享
安装VMware Tools: 选择菜单栏“虚拟机”——“安装VMware tools” ,等待系统自动更换ISO光盘 mount /dev/cdrom /mntcd /mnttar zxvf VMw ...
- Struts2 技术全总结 (正在更新)
背景:Struts1是一个高度成熟的框架,运行效率高,但其致命缺陷在于与JSP/Servlet的耦合非常紧密,因而导致了一些严重问题.其次,Struts1与Servlet API的严重耦合,使应用难以 ...
- 探索A@1db9742
public class S { /** * @param args */ public static void main(String[] args) { System.out.printl ...
- HEAP[xxx.exe]:Invalid Address specified to RtlValidateHeap 错误的解决方法总结
一.情况 抽象出问题是这样的: class DLL_API1 A { func() { vector vec; B b; b.func(vec); return TRUE; } } 其中B是另一个导出 ...
- HTML5简介、视频
HTML5 建立的一些规则: 新特性应该基于 HTML.CSS.DOM 以及 JavaScript. 减少对外部插件的需求(比如 Flash) 更优秀的错误处理 更多取代脚本的标记 HTML5 应该独 ...
- mongodb的连接问题,绑定IP惹的祸
刚刚安装好了 mongodb .对着 mongodb in action上的例子敲了下面的代码: public class TestDBConnect { @Test public void test ...
- PHP第二课笔记
★Php的基本概念 快速入门案例 test.php <html> <body> //<?php ?>是运行在服务端 <?php echo 'hello' ...