#counter #thread #thread-safe #atomic #order #memory #consistent

atomic-counter

Rust 的原子(线程安全)计数器

3 个版本 (稳定)

使用旧的 Rust 2015

1.0.1 2018 年 9 月 27 日
1.0.0 2018 年 9 月 26 日
0.1.0 2017 年 9 月 8 日

#469并发

Download history 10022/week @ 2023-11-21 11057/week @ 2023-11-28 11608/week @ 2023-12-05 12141/week @ 2023-12-12 8317/week @ 2023-12-19 3554/week @ 2023-12-26 9811/week @ 2024-01-02 9271/week @ 2024-01-09 10164/week @ 2024-01-16 9962/week @ 2024-01-23 8656/week @ 2024-01-30 11869/week @ 2024-02-06 12365/week @ 2024-02-13 13224/week @ 2024-02-20 13141/week @ 2024-02-27 10710/week @ 2024-03-05

52,231 每月下载量
用于 18 个 crate (15 个直接使用)

MIT 许可证

18KB
204

AtomicCounter

Rust 的原子(线程安全)计数器。

这个 crate 包含了一个可以安全地在线程之间共享的 AtomicCounter trait。

这个 crate 提供了两个实现

两个实现都是无锁的。两者都是基于 AtomicUsize 的一层薄薄的封装,它更强大,但可能更难正确使用。

使用哪个计数器

  • 如果您只是收集指标,那么 RelaxedCounter 可能是正确的选择。

  • 如果您正在生成 ID,但没有做出强烈的假设(例如,根据 ID 计数分配内存),则 RelaxedCounter 可能是正确的选择。

  • 如果您正在生成多个 ID,并保持顺序不变性(例如,ID a 总是大于 ID b),则需要“顺序一致性”,因此需要使用 ConsistentCounter。同样适用于所有需要计数器增加顺序的用例。

不会丢失更新 - 只关乎顺序!

请注意,在这两个实现中,不会丢失计数,所有操作都是原子的。差异仅在于不同线程观察到的操作顺序。

示例

假设 a 为 5,b 为 4。你总是想保持 a > b

线程 1 执行此代码


a.inc();
b.inc();

线程 2 获取计数


let a_local = a.get();
let b_local = b.get();

a_localb_local 的值是多少?这取决于线程 1 和 2 的运行顺序。

  • 如果线程 2 在线程 1 之前运行,a_local 仍可能是 5,而 b_local 仍可能是 4。
  • 如果线程 1 和 2 并行运行,a_local 可能为 6,而 b_local 仍为 4。
  • 如果线程 2 在线程 1 之后运行,a_local 可能为 6,而 b_local 可能为 5。
  • 此外,如果至少有一个计数器是 RelaxedCounter,我们无法假设 a.inc()b.inc() 的顺序。因此,在这种情况下,线程 2 可能会观察到 a_local 为 5(尚未增加)而 b_local 增加到 5,违反了不变量 a > b。请注意,如果线程 2(或任何其他线程)再次 get() 计数,它们将在某个时刻观察到两个值都增加了。不会有操作丢失。只是在 OrderingRelaxed 时,无法假设操作的 顺序

因此,为了在多个线程之间保持如 a > b 这样的不变量,请使用 ConsistentCounter

无运行时依赖