?um/p1-90`内存一致性模型,或称 内存模型,用于指定
内存模型被定义为作用于 Memory 事件的关系约束,这些事件是由对 SharedArrayBuffer 的
共享内存访问(读与写)分为两类:原子访问和数据访问(下文定义)。原子访问是顺序一致的,即存在一个所有代理都同意的
不支持比顺序一致更弱、比无序更强的次序(如 release-acquire)。
共享数据块事件是指 ReadSharedMemory、WriteSharedMemory 或 ReadModifyWriteSharedMemory 记录之一。读事件是指 ReadSharedMemory 或 ReadModifyWriteSharedMemory。写事件是指 WriteSharedMemory 或 ReadModifyWriteSharedMemory。
| 字段名 | 取值 | 含义 |
|---|---|---|
| [[Order]] | ||
| [[NoTear]] | 布尔值 | 该事件是否允许从多个与自身 |
| [[Block]] | 一个共享数据块 | 事件所操作的数据块。 |
| [[ByteIndex]] | 非负整数 | [[Block]] 中读取的字节地址。 |
| [[ElementSize]] | 非负整数 | 读取的大小。 |
| 字段名 | 取值 | 含义 |
|---|---|---|
| [[Order]] | ||
| [[NoTear]] | 布尔值 | 该事件是否允许被来自相同 |
| [[Block]] | 一个共享数据块 | 事件所操作的数据块。 |
| [[ByteIndex]] | 非负整数 | 在 [[Block]] 内写入的字节地址。 |
| [[ElementSize]] | 非负整数 | 写入的大小。 |
| [[Payload]] | 可被其他事件读取的 |
| 字段名 | 取值 | 含义 |
|---|---|---|
| [[Order]] | 读-改- |
|
| [[NoTear]] | 读-改- |
|
| [[Block]] | 一个共享数据块 | 事件操作的块。 |
| [[ByteIndex]] | 一个非负整数 | 在 [[Block]] 中读改写的字节地址。 |
| [[ElementSize]] | 一个非负整数 | 读改写的大小。 |
| [[Payload]] | 一个 |
传递给 [[ModifyOp]] 的 |
| [[ModifyOp]] | 一个读-改-写修改函数 | 从读取的 |
共享数据块事件是通过
令共享数据块事件 e 的内存区间为从 e.[[ByteIndex]](包含)到 e.[[ByteIndex]] + e.[[ElementSize]](不包含)之间所有整数的集合。当两个事件拥有相同的 [[Block]]、[[ByteIndex]] 和 [[ElementSize]] 时,它们的内存区间相等。若两个事件拥有相同的 [[Block]],
应考虑的postMessage),代理的启动与停止,以及通过共享内存之外的通道在代理集群内通信。对于某次执行 execution,这些事件由
候选执行中的事件由下列定义的关系排序。
Agent Events Record 是具有以下字段的
Chosen Value Record 是具有以下字段的
| 字段名 | 取值 | 含义 |
|---|---|---|
| [[Event]] | 一个 |
为该选定值引入的 |
| [[ChosenValue]] | 一个 |
求值过程中非确定性选出的字节。 |
代理集群求值的一个 candidate execution 是具有以下字段的
| 字段名 | 取值 | 含义 |
|---|---|---|
| [[EventsRecords]] | 代理事件记录的列表 | 将代理映射到求值过程中追加的 |
| [[ChosenValues]] | 已选值记录的列表 | 将 |
The abstract operation EventSet takes argument execution (一个候选执行) and returns 一个 Memory 事件的集合. It performs the following steps when called:
The abstract operation SharedDataBlockEventSet takes argument execution (一个候选执行) and returns 一个
The abstract operation HostEventSet takes argument execution (一个候选执行) and returns 一个 Memory 事件的集合. It performs the following steps when called:
The abstract operation ComposeWriteEventBytes takes arguments execution (一个候选执行), byteIndex (一个非负整数), and Ws (
读-改-写的修饰操作 [[ModifyOp]] 由引入
该
The abstract operation ValueOfReadEvent takes arguments execution (a
以下关系与数学函数以特定候选执行为参数,对其事件排序。
以下关系和数学函数是以特定的候选执行为参数,对其 Memory 事件进行排序。
对于候选执行 execution,其 is-agent-order-before 关系是在 Memory 事件上的最小关系,满足以下条件。
对于候选执行 execution,其 reads-bytes-from 函数是一个数学函数,将
对于
一个候选执行总是允许一个 reads-bytes-from 函数存在。
对于候选执行 execution,其 reads-from 关系是在 Memory 事件上的最小关系,满足以下条件。
对于候选执行 execution,其 host-synchronizes-with 关系是在
对于候选执行 execution 中的两个
该关系允许postMessage。
对于候选执行 execution,其 synchronizes-with 关系是在 Memory 事件上的最小关系,满足以下条件。
在候选执行 execution 中,
在候选执行 execution 中,并非所有通过
对于候选执行 execution 中的
对于候选执行 execution,其 happens-before 关系是在 Memory 事件上的最小关系,满足下列条件。
对于事件 E 和 D,只要下列任何条件成立,则 E happens-before D in execution。
由于 happens-before 是 agent-order 的超集,候选执行与 ECMAScript 的单线程求值语义一致。
若下述算法返回
若下述算法返回
若下述算法返回
通过访问整型
直观来说,这一要求意味着:当通过整型
对于候选执行 execution,is-memory-order-before 是对
对于满足 R
本条进一步约束了相同
对于
候选执行有顺序一致原子操作,当且仅当它允许存在 is-memory-order-before 关系。
虽然 is-memory-order-before 包含
若候选执行 execution 满足如下所有条件,则称其为有效执行(或简称执行)。
所有程序至少有一个有效执行。
对于 execution execution 和已包含在
对于 execution execution 和
若
若某程序的所有执行都无数据竞争,则该程序是无数据竞争的。
以下是 ECMAScript 程序员在使用共享内存时的相关建议。
我们建议程序保持
更一般来说,即使程序不是
以下是 ECMAScript 实现者针对使用共享内存的程序编译器转换的建议。
在多 agent 环境下,允许大多数在单 agent 环境中有效的程序变换是很有必要的,这样可以确保多 agent 程序中每个 agent 的性能不会低于其在单 agent 情境下的表现。然而,这些变换通常难以评判。我们在此概述了一些关于程序变换的规范性规则(即这些规则要么隐含于
定义 agent-order 切片 为
定义某次
任何在无共享内存场景下有效的 agent-order 切片转换,在有共享内存下同样有效,但需遵循以下例外:
原子操作不可改变:程序变换不得导致
(实际上,对重排序的禁止迫使编译器假定每个
读取需稳定:每个共享内存读取在一次执行中只能见到唯一值。
(例如,若语义上是一次读取而程序实际执行了多次,那么之后程序只允许观察到其中一个读取结果。rematerialization 等变换会破坏这个规则。)
写入需稳定:所有可观察到的对共享内存的写都必须基于执行过程产生。
(如:某些变换不得引入新的可观察写入,比如用对更大内存的读改写操作写入小数据,在程序无法写出的值被写入、或者读取后又立即写回,而该地址可能已被其它 agent
读取的可能值不能为空:程序变换不得导致某次共享内存读取的"可能读取值"集合为空。
(直观上,这一规则实则限制了对写的变换,因为写只有能被读到才有模型效力。例如,允许合并/重排序写,但不得移除全部写入,否则可能会让某次读取无值可读。)
例如:合并同一地址的多次非原子读取、重排序非原子读取、引入投机性非原子读取,合并同一地址的多次非原子写、重排序写到不同地址的非原子写,以及将非原子读取提出循环体外甚至影响终止性等,都是有效的变换。但需要注意别名
以下是 ECMAScript 实现者在为共享内存访问生成机器码时的建议。
对于LOCK 前缀、ARM 的 load-exclusive/store-exclusive、Power 的 load-link/store-conditional。
本
朴素代码生成模式如下:
只要原子操作的
对上述模式的局部优化也是允许的,只要遵循
LOCK 前缀)。多数平台有不同强度的屏障,根据场景可用更弱屏障而不破坏顺序一致性。