5 个版本
使用旧的 Rust 2015
0.2.3 | 2023 年 3 月 21 日 |
---|---|
0.2.2 | 2020 年 10 月 6 日 |
0.2.1 | 2018 年 11 月 14 日 |
0.2.0 | 2018 年 11 月 14 日 |
0.1.0 | 2018 年 3 月 28 日 |
#791 in 并发
每月 150 次下载
20KB
197 行
进程级内存屏障
内存屏障是现代松散内存并发中最强大的同步原语之一。在松散内存并发中,两个线程可能对底层内存系统有不同的观点,例如线程 T1 可能已经识别出在位置 X 的值 V,而 T2 完全不知道 X=V。这种差异是并发编程困难的主要原因之一。内存屏障通过这种方式同步线程,使得在内存屏障之后,线程对底层内存系统有相同的观点。
不幸的是,内存屏障并不便宜。通常,在现代计算机系统中,有一个专门的内存屏障指令,例如 x86 中的 MFENCE
和 ARM 中的 DMB SY
,它们可能需要超过 100 个周期。内存屏障指令的使用可能在某些用例中可以忍受,例如少数线程的上下文切换,或同步在长时间运行过程中只发生一次的事件。然而,有时在快速路径上使用内存屏障是必要的,这会显著降低性能。
为了减少内存屏障的同步成本,Linux 和 Windows 提供了“进程级内存屏障”,这基本上是对进程中的每个线程执行内存屏障。尽管它比普通内存屏障指令慢,但有什么好处呢?以进程级内存屏障的代价,其他线程可以免除发出内存屏障指令!换句话说,通过使用进程级内存屏障,您可以在慢速路径的性能成本下优化快速路径。
对于进程级内存屏障,Linux 最近引入了 sys_membarrier()
系统调用,但已知在较老的 Linux 中,带有适当参数的 mprotect()
系统调用提供了进程级内存屏障语义。Windows 提供了 FlushProcessWriteBuffers()
API。
用法
如下使用此 crate
extern crate membarrier;
use std::sync::atomic::{fence, Ordering};
membarrier::light(); // light-weight barrier
membarrier::heavy(); // heavy-weight barrier
fence(Ordering::SeqCst); // normal barrier
语义
正式来说,内存屏障有三种类型:轻量级屏障(membarrier::light()
)、重量级屏障(membarrier::heavy()
)和普通屏障(fence(Ordering::SeqCst)
)。在程序的执行过程中,所有内存屏障实例之间存在一个总顺序。如果线程A发出屏障X,线程B发出屏障Y,且X在Y之前,则在Y之后,A对X时刻底层内存系统的了解将传递给B,前提是
- A或B的屏障是重量级的;或者
- A和B的屏障都是普通的。
参考
有关更多信息,请参阅Linux man
页面的membarrier
(http://man7.org/linux/man-pages/man2/membarrier.2.html)。
依赖
~21–29MB
~383K SLoC