内存级别/栅栏 ( Memory Barriers / Fences ) – 翻译
翻译自:Martin Thompson – Memory
Barriers/Fences
在这篇文章里,我将讨论并发编程里最基础的技术–以内存关卡或栅栏著称。那让进程内的内存状态对其它进程可见。
CPU 使用了非常多技术去尝试和适应这种事实:CPU 运行单元的性能已远远超出主内存性能。在我的“Writing
Combining”文章,我仅仅是谈及当中一种技术。
CPU 使用的用来隐藏内存延迟的最普通技术是管线化指令。然后付出巨大努力和资源去尝试重排序这些管线来最小化缓存不命中的有关迟延。
当一个程序运行的时候。它不在乎。假设重排序后的指令提供了一样的终于结果。比如,在一个循环内。假设循环内没有操作使用循环计算器。循环计数器什么时候更新是不在乎的。编译器和 CPU 自由地重排序指令来最大化地利用 CPU,直到下一次迭代即将開始时才更新它(循环计数器)。
也可能,在一个循环的运行过程中。这个变量可能存储在一个寄存器里。永远不会推到缓存或主内存。因此,它对其他 CPU 永远不可见。
CPU 核包括多个运行单元。
比如。一个现代的Intel CPU 包括6个运行单元。能够做一组数学。条件逻辑和内存操作的组合。每一个运行单元能够做这些任务的组合。
这些运行单元并行地操作,同意指令并行地运行。假设从其他 CPU 来观察,这引入了程序顺序的还有一层不确定性。
终于,但缓存不命中发生时,现代 CPU 能够依据内存载入的结果做一个如果,然后基于这个如果继续运行直至实际数据的载入完毕。
提供“程序顺序”保留了 CPU 和编译器自由地做它们觉得能够提升性能的事情。
载入(load)和存储(store)到缓存和主内存是被缓冲和重排序的,使用载入(load),存储(store),和写组合(writing-combining)缓存。
这些缓存是关联的队列,同意高速查找。这样的查找是必须的,当一个稍后的载入须要读取一个之前存储的、还没有到达缓存的值时。上图描绘了现代多核 CPU 的简化视图。它显示了运行单元怎样使用本地寄存器和缓存来管理内存,与缓存子系统来回传送。
在多线程环境下,须要採用一些技术来让程序结果及时可见。
我不会在这篇文章里涉及缓存一致性。只如果一旦内存被推到缓存。然后有一个协议消息将发生。以确保全部共享数据的缓存是一致的。这样的使内存对处理器核可见的技术被称为内存关卡或栅栏。
内存关卡提供了两种属性。首先,它们保留了外部可见的程序顺序。通过确保全部的、关卡两側的指令表现出正确的程序顺序。假设从其它CPU观察。第二,它们使内存可见,通过确保数据传播到缓存子系统。
内存关卡是一个复杂的主题。它们在不同的 CPU 架构上的实现是很不同的。Intel CPU 有一个关联的强内存模型。本篇将以 x86 CPU 为基础解说。
存储关卡(store barrier)
存储关卡,在x86 上是”sfence”指令,强迫全部的、在关卡指令之前的 存储指令在关卡曾经发生,而且让 store buffers 刷新到公布这个指令的 CPU cache。这将使程序状态对其它 CPU 可见,这样,假设须要它们能够对它做出响应。一个实际的好样例是以下的、简化的、来自Disruptor的类BatchEventProcessor。当sequence被更新后。其它消费者和生产者知道这个消费者的进展。并进行适当的响应。全部在关卡之前对内存的更新如今都可见了。
private volatile long sequence = RingBuffer.INITIAL_CURSOR_VALUE;
// from inside the run() method
T event = null;
long nextSequence = sequence.get() + 1L;
while (running)
{
try
{
// 译注:barrier 会读取其它sequence 的值。所以这里面有个 load barrier 指令。
final long availableSequence = barrier.waitFor(nextSequence);
while (nextSequence <= availableSequence)
{
event = ringBuffer.get(nextSequence);
boolean endOfBatch = nextSequence == availableSequence;
eventHandler.onEvent(event, nextSequence, endOfBatch);
nextSequence++;
}
sequence.set(nextSequence - 1L);
// store barrier 插入到这里 !!!
}
catch (final Exception ex)
{
exceptionHandler.handle(ex, nextSequence, event);
sequence.set(nextSequence);
// store barrier 插入到这里 !!!
nextSequence++;
}
}
载入关卡(load barrier)
载入关卡。在x86 上是”lfence”指令,强迫全部的、载入指令之后的指令在关卡之后发生,然后等待那个 CPU 的 load buffer 排空。
这使其他 CPU 暴露出来的程序状态对这个 CPU 可见。在做出很多其他进展之前。
这个的一个好样例是前面引用的 BatchEventProcessor 的 sequence 被其他生产者或消费者读取时,Disruptor 里有等价的指令。
Full Barrier
Full Barrier。在x86 上是”mfence”指令,在 CPU 上是载入和存储关卡的组合。
Java 存储模型(Java Memory Model)
在Java 存储模型里,volatile 字段在写入后插入一个存储关卡,在读取前插入载入关卡。类里面修饰为 final 的字段在它们被初始化后插入一个存储指令,以确这些字段在构造函数完毕、有可用引用到这个对象时是可见的。
原子指令和软件锁(Atomic Instructions and Software Locks)
原子指令,如x86里的 “lock …” 指令,是高效的 full barrier,它们锁住存储子系统来运行操作。有受保证的全序关系(total order),即使跨 CPU。软件锁通常使用存储关卡,或原子指令来达到可视性和保留程序顺序。
存储关卡对性能的影响(Performance Impact of Memory Barriers)
存储关卡阻止了 CPU 运行非常多隐藏内存延迟的技术,因此有它们有显著的性能开销,必须考虑。为了达到最大性能。最好对问题建模,这样处理器能够做工作单元,然后让全部必须的存储关卡在工作单元的边界上发生。採用这样的方法同意处理器不受限制地优化工作单元。
把必须的存储关卡分组是故意的,那样,在第一个之后的 buffer 刷新的开销会小点。由于没有工作须要进行又一次填充它。
译注:关于Disruptor能够看我之前的这篇文章:http://coderbee.net/index.php/open-source/20130812/400
原文地址:http://coderbee.net/index.php/concurrent/20131211/624;
内存级别/栅栏 ( Memory Barriers / Fences ) – 翻译的更多相关文章
- 什么是内存屏障? Why Memory Barriers ?
要了解如何使用memory barrier,最好的方法是明白它为什么存在.CPU硬件设计为了提高指令的执行速度,增设了两个缓冲区(store buffer, invalidate que ...
- 洛谷P2731 骑马修栅栏 Riding the Fences
P2731 骑马修栅栏 Riding the Fences• o 119通过o 468提交• 题目提供者该用户不存在• 标签USACO• 难度普及+/提高 提交 讨论 题解 最新讨论 • 数据有问题题 ...
- Android 内存管理 &Memory Leak & OOM 分析
1.Android 流程管理&内存 Android主要应用在嵌入式设备其中.而嵌入式设备因为一些众所周知的条件限制,通常都不会有非常高的配置,特别是内存是比較有限的. 假设我们编写的代 码其中 ...
- Memory Barriers
这回该进入主题了. 上一文最后提到了 Memory Barriers ,即内存屏障.由于对一个 CPU 而言,a = 1; b = 1. 由于在中间加了内存屏障,在 X86 架构下,就 ...
- Synthesis of memory barriers
A framework is provided for automatic inference of memory fences in concurrent programs. A method is ...
- Java内存模型(Java Memory Model,JMM)
今天简单聊聊什么叫做 Java 内存模型,不是 JVM 内存结构哦. JMM 是一个语言级别的内存模型,处理器的硬件模型是硬件级别,Java中的内存模型是内存可见性的基本保证.从而为我们 volati ...
- 内存转储文件 Memory.dmp
https://baike.sogou.com/v63435711.htm?fromTitle=内存转存文件 内存转储是用于系统崩溃时,将内存中的数据转储保存在转储文件中,供给有关人员进行排错分析用途 ...
- 【并行计算-CUDA开发】关于共享内存(shared memory)和存储体(bank)的事实和疑惑
关于共享内存(shared memory)和存储体(bank)的事实和疑惑 主要是在研究访问共享内存会产生bank conflict时,自己产生的疑惑.对于这点疑惑,网上都没有相关描述, 不管是国内还 ...
- 内存管理(memory allocation内存分配)
Memory management is the act of managing computer memory. The essential requirement of memory manage ...
随机推荐
- IE Jquery中拒绝訪问的处理方法
多人合作开发一个站点过程中,为便于开发,将一些公共文件如js,css,images放在外网上,各自链接这类文件以供使用.本地測试时网页的一些JS代码在IE8,IE6中会停止运行,并报某个js文件拒绝訪 ...
- 组件状态(TComponentState)11种和组件状态(TComponentStyle)4种
TOperation = (opInsert, opRemove); TComponentState = set of ( csAncestor The component was introduce ...
- 基于visual Studio2013解决C语言竞赛题之1079狼羊过河
题目 解决代码及点评 /************************************************************************/ /* ...
- poj 2777 Count Color(线段树区区+染色问题)
题目链接: poj 2777 Count Color 题目大意: 给出一块长度为n的板,区间范围[1,n],和m种染料 k次操作,C a b c 把区间[a,b]涂为c色,P a b 查 ...
- [置顶] 64位Win2008_VS2012使用ODP.NET遭遇问题和解决办法
最近为使用Oracle11G数据库做个快速开发的小程序,使用64位Win2008+Vs2012环境,结果碰壁连环,幸好不算太笨,终于解决了,特记录一下. 测试环境: Oracle11g (11.2.0 ...
- [Unity3D]Unity3D游戏开发之《愤慨的小鸟》弹弓实现
各位朋友,大家晚上好, 我是秦元培.欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.今天我们来做一个高端大气上档次的东西. 我相信大家都玩过一款叫做<愤慨的 ...
- Sencha app build 出现 missing name after . operator 问题
此问题是在使用sencha app build命令后出现得 主要是 YUI Compressor压缩的时候,代码中出现了delete, interface之类的keyword导致的. 此时能够在Web ...
- Tomcat详细用法学习(四)
本篇接上一篇<Tomcat详细用法学习(三)>,主要讲解配置虚拟主机.打包web应用成war包和Tomcat的体系结构 对于Tomcat服务器,可以放置多个网站(多个web应用),这就是讲 ...
- 重操JS旧业第一弹:Script与JS加载
不管js被包装成什么样子,最终交给浏览器执行的js都是原生的,都离不开原生js的原理. Script标签纸html中用来加载js的标签,我们知道js可以是来自外部,本地,或者内部一段代码,在这里只讨论 ...
- JavaScript快速入门(六)——DOM
概念扫盲 DOM DOM是 Document Object Model(文档对象模型)的缩写,是W3C(万维网联盟)的标准.DOM 定义了访问 HTML 和 XML 文档的标准:“W3C 文档对象模型 ...