作者:doug lea 翻译:古圣昌 校对:欧振聪,方腾飞
<a href="http://ifeve.com/jsr-cookbook-reorderings/" target="_blank">指令重排</a>
<a href="http://ifeve.com/jmm-cookbook-mb/">内存屏障</a>
<a href="http://ifeve.com/jmm-cookbook-mps/" target="_blank">多处理器</a>
<a href="http://ifeve.com/cookbook-recipes/" target="_blank">指南</a>
本文总结了在多处理器(mps)中常用的的处理器列表,处理器相关的信息都可以从链接指向的文档中得到(一些网站需要通过注册才能得到相应的手册)。当然,这不是一个完全详细的列表,但已经包括了我所知道的在当前或者将来java实现中所使用的多核处理器。下面所述的关于处理器的列表和内容也不一定权威。我只是总结一下我所阅读过的文档,但是这些文档也有可能是被我误解了,一些参考手册也没有把java内存模型(jmm)相关的内容阐述清楚,所以请协助我把本文变得更准确。
sparc-tso
x86 (和 x64)
ia64
ppc (power)
arm
pa-risc
下面是这些处理器所支持的屏障和原子操作:
<b>processor</b>
<b>loadstore</b>
<b>loadload</b>
<b>storestore</b>
<b>storeload</b>
<b>data</b>
dependency
orders loads?
<b>atomic</b>
conditional
<b>other</b>
atomics
<b>atomics</b>
provide
barrier?
不执行操作
membar
(storeload)
是
cas:
casa
swap,
ldstub
全部
x86
mfence or
cpuid or
locked insn
cmpxchg
xchg,
combine
和
st.rel 或者
ld.acq
st.rel
mf
fetchadd
部分 +
acq/rel
dmb
(见下文)
dmb-st
只能间接
ll/sc:
ldrex/strex
仅针对部分
ppc
lwsync
hwsync
ldarx/stwcx
alpha
mb
wmb
否
ldx_l/stx_c
build
from
ldcw
无
说明:
尽管上面一些单元格中所列的屏障指令比实际需要的特性更强,但可能是最廉价的方式获得所需要的效果。
上面所列的屏障指令主要是为正常的程序内存的使用而设计的,io和系统任务就没有必要用特别形式/模式的缓存和内存。举例来说,在x86 spo中,storestore屏障指令(“sfence”)需要写合并(wc)缓存模式,其目的是用在系统级的块传输等地方。操作系统为程序和数据使用写回(writeback)模式,这就不需要storestore屏障了。
在x86中,任何lock前缀的指令都可以用作一个storeload屏障。(在linux内核中使用的形式是无操作的lock指令,如addl $0,0(%%esp)。)。除非必须需要使用像cas这样lock前缀的指令,否则使用支持sse2扩展版本(如奔腾4及其后续版本)的mfence指令似乎是一个更好的方案。cpuid指令也是可以用的,但是比较慢。
在ia64平台上,loadstore,loadload和storestore屏障被合并成特殊形式的load和store指令–它们不再是一些单独的指令。ld.acq就是(load;loadload+loadstore)和st.rel就是(loadstore+storestore;store)。这两个都不提供storeload屏障–因此你需要一个单独的mf屏障指令。
sparc membar指令不但支持所有的4种屏障模式,而且还支持组合模式。但是storeload模式需要在tso中。在一些ultrasparcs中,不管任何模式下membar指令总是能让storeload生效。
在与这些流指令有关的情况中,x86处理器支持”streaming simd” sse2扩展只需要loadload ‘lfence’
虽然pa-risc规范并不强制规定,但所有hp pa-risc的实现都是顺序一致,因此没有内存屏障指令。
在不同的字段宽度(field width,包括4个字节和8个字节版本)里,cas和ll/sc在不同的处理器上会使用多种形式。
在sparc和x86处理器中,cas有隐式的前后全storeload屏障。sparcv9架构手册描述了cas不需要post-storeload屏障特性,但是芯片手册表明它确实在ultrasparcs中存在这个特性。
只有在内存区域进行加载和存储(loaded/stored)时,ppc和alpha, ll/sc才会有隐式的屏障,但它不再有更通用的屏障特性。
在内存区域中进行加载或存储时, ia64 cmpxchg指令也会有隐式的屏障,但还会额外加上可选的.acq(post-loadload+loadstore)或者.rel(pre-storestore+loadstore)修改指令。cmpxchg.acq形式可用于monitorenter,cmpxchg.rel可用于monitorexit。在上述的情况中,exits和enters在没有被确定匹配的情况下,就需要exitenter(storeload)屏障。
sparc,x86和ia64平台支持unconditional-exchange (swap, xchg). sparc ldstub是一个one-byte test-and-set。 ia64 fetchadd返回前一个值并把它加上去。在x86平台,一些指令(如add-to-memory)能够使用lock前缀的指令执行原子操作。