5 个不稳定版本
0.2.1 | 2022年5月29日 |
---|---|
0.2.0 | 2022年5月8日 |
0.1.1 | 2022年3月29日 |
0.1.0 | 2022年3月29日 |
0.0.0 | 2020年10月8日 |
#517 在 并发 中
每月下载量 36
155KB
2.5K SLoC
usync
此库提供了 Mutex
、RwLock
、Condvar
、Barrier
和 Once
的实现,它们的大小为字大小,通常与 parking_lot
中的实现一样快。它还提供了一个支持递归加锁的 ReentrantMutex
类型。
功能
此库提供的原语与 Rust 标准库中的原语相比具有多个优势
- 所有类型只需要 1 个字的空间。另一方面,标准库中的原语需要动态分配的
Box
来持有特定于操作系统的同步原语。特别是Mutex
的大小较小,这鼓励使用细粒度锁来增加并行性。 - 由于它们仅由一个原子变量组成,具有常量初始化器并且不需要析构函数,因此这些原语可以用作
static
全局变量。标准库中的原语需要动态初始化,因此需要使用lazy_static!
惰性初始化。 - 无竞争锁的获取和释放通过快速内联路径完成,这些路径只需要一次原子操作。
- 微内容竞争(具有短暂临界区的竞争锁)通过在尝试获取锁时旋转几次来有效地处理。
- 锁是自适应的,在几次失败的旋转尝试后挂起线程。这使得锁适合长和短临界区。
Condvar::notify_all
通常只会唤醒一个线程,并将其余线程重新排队以等待关联的Mutex
。这避免了所有线程同时尝试获取锁的暴风骤雨问题。Mutex
和RwLock
允许在没有 RAII 保护对象的情况下进行原始解锁。Mutex<()>
和RwLock<()>
允许在不使用 RAII 保护对象的情况下进行原始锁定。- 支持递归锁定的
ReentrantMutex
类型。 - 当启用
send_guard
功能时,锁保护可以被发送到其他线程。
用户空间队列
为了使这些原始数据类型保持字大小,它们的状态在计数器、线程队列以及两者的组合之间进行复用。这类似于 Windows 的 Slim Synchronization Primitives。不采用 Linux futex 或 parking_lot 中所见到的全局队列的外部锁定。这些队列都嵌入在每个原始数据类型中,并通过无锁操作进行交互,以降低最坏情况下的争用延迟。
不幸的是,由于需要处理与同步状态相关的队列,因此无法保证 Condvar
的“无虚假唤醒”,并且 RwLock
的极端只读工作流程无法使用优化的原子操作来提高吞吐量。尽管如此,这些性能限制在实践中并不重要,尤其是在其他缓存效果发挥作用时。另一方面,写入/独占重负载比现有解决方案具有更好的可扩展性,并且针对微争用进行了大量优化。
夜间与稳定版
在稳定版 Rust 上使用此库时有一些限制
- 您必须使用
const_*
函数(例如const_mutex(val)
)来静态初始化锁定原始数据类型。在稳定版 Rust 中,使用例如Mutex::new(val)
还不起作用。
要启用夜间专属功能,您需要在 Cargo 中启用 nightly
功能(见下文)。
使用方法
将此添加到您的 Cargo.toml
[dependencies]
usync = "0.2.1"
要启用夜间专属功能,请将此添加到您的 Cargo.toml
中代替
[dependencies]
usync = { version = "0.2.1", features = ["nightly"] }
要允许将 MutexGuard
和 RwLock*Guard
发送到其他线程,请启用 send_guard
选项。
许可证
在 MIT 许可证下授权(LICENSE-MIT 或 http://opensource.org/licenses/MIT)。
依赖项
~160KB