天天看点

Java内存模型Cookbook(三)多处理器

作者: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前缀的指令执行原子操作。