程序顺序与外部观察顺序

编译器和处理器可以在保持适用程序语义的前提下重排、合并或推测执行。一个CPU上写在前面的访问,未必就以同样顺序被另一CPU或设备观察到;屏障为需要通信的操作补充明确的顺序约束。

屏障的方向和范围必须说明。Linux的写屏障主要约束前后写操作,读屏障和更强的屏障有不同保证;获取与释放操作又提供方向性的约束。不能把所有名称中含“屏障”的机制都当作同一种全局停顿。

参考:[1]

以RISC-V的FENCE为例

RISC-V FENCE用前驱与后继集合说明要排序的操作类别,包括设备输入I、设备输出O、内存读R和内存写W。程序可以按需要约束这些类别,不能只看到FENCE名称就假定它总是同样强度的指令。

这项顺序规则针对所规定的内存和I/O访问观察。设备通过额外线路发出中断的时机不因此自动得到相同保证;确认设备状态、处理通知和进行内存同步,仍需遵守设备与平台自己的协议。

参考:[2]

屏障不提供哪些保证

编译器屏障与CPU屏障解决不同层次的问题;仅限制编译器移动访问,不一定限制硬件对外呈现的顺序。另一端也需要与协议匹配的读取或获取操作,不能在发送端任意加一道屏障,就认定所有观察者都会按预期读取。

屏障也不会让复合操作自动不可分割,或让两个线程不能同时进入临界区。缓存维护、DMA缓冲区所有权和总线写入完成各有接口;正确同步应先说明需要建立什么先后关系,再选择满足它的原语。

参考:[1] [3] [4]