2 个版本

0.1.1 2019 年 7 月 5 日
0.1.0 2019 年 7 月 5 日

#214 in 缓存

MIT/Apache

65KB
935

Hazptr

基于危害指针的并发无锁内存回收。

Build Status Latest version Documentation License Rust 1.36+

每当一个线程从共享内存读取一个值时,它也会用全局可见的 危害指针 保护所加载的值。所有线程都可以 退役 不再需要且可访问的共享值,并将其本地缓存。退役的记录会成批回收(丢弃和重新分配),但只有当它们不再或不再由任何危害指针保护时。

使用方法

将此添加到您的 Cargo.toml

[dependencies]
hazptr = "0.1"

最低支持 Rust 版本 (MSRV)

此包最低支持的 Rust 版本是 1.36.0。

crossbeam-epoch 的比较

危害指针回收方案通常不如基于纪元的回收方案(或其他类型的回收方案)高效。这主要是因为获取危害指针需要在每次从共享内存加载后执行昂贵的内存栅栏。然而,它在回收可靠性方面通常是最佳的方案。退役的记录通常会及时回收,并且回收不会受到竞争的影响。这些属性可能导致使用危害指针而不是其他回收方案的应用程序具有更好的内存占用。此外,由于危害指针只保护单个指针免于回收,因此它们可能更适合保护单个记录较长时间。另一方面,基于纪元的方案在记录需要保护时完全防止所有线程的回收。

示例

有关使用危害指针实现 Treiber 栈的示例,请参阅 examples/treiber/stack.rs,或有关并发哈希集实现的示例,请参阅 examples/hash_set/ordered.rs

功能

为此包定义了以下功能

  • std (默认)
  • count-release

默认情况下,线程在退役了一定数量的记录后,会启动 GC 扫描并尝试清除其缓存中的退役记录。通过使用 count-release 功能编译包,可以将此更改为计算成功获取的危害指针 Guard 的实例数(即释放)。这在只有少量记录且退役很少的情况下可能有益。

扫描频率

用于确定GC扫描频率的阈值可以通过HAZPTR_SCAN_THRESHOLD环境变量进行自定义。此变量可以是任何正的非零32位整数,默认值为100,即在不传递构建过程中的环境变量时。阈值为1表示,例如,在每次计数达到阈值后的操作都会触发GC扫描,这意味着退休记录或释放Guard的操作,如果启用了count-release功能。可以通过使用cargo来指定此环境变量。

env HAZPTR_SCAN_THRESHOLD=1 cargo build

或者,此变量也可以在构建脚本中设置。

// build.rs

fn main() {
    // alternative: std::env::set_var("HAZPTR_SCAN_THRESHOLD", "1")
    println!("cargo:rustc-env=HAZPTR_SCAN_THRESHOLD=1");
}

为了强制以新值重建,在设置此变量后,有必要先调用cargo clean

一般来说,较高的扫描阈值在性能方面更好,因为线程需要更频繁地尝试回收记录,但可能会导致大量垃圾的积累,并降低性能。

#[no_std]环境中使用

当构建不带(默认)std功能的crate时,可以在#[no_std] + alloc环境中使用其功能,尽管可能存在争议的易用性。在此配置中,crate的公共API还公开了Local类型。此外,不是导出Guard类型,而是导出不同的LocalGuard类型,该类型包含对线程局部状态的显式引用。

为了在这样的环境中使用hazptr,必须手动执行以下步骤

  • 对于每个线程,创建一个单独的Local实例
  • 危险指针只能通过显式传递当前线程的Local实例的引用来创建

许可证

Hazptr在MIT许可证和Apache许可证(版本2.0)的条款下分发。

有关详细信息,请参阅LICENSE-APACHELICENSE-MIT

依赖关系

~460KB