#ring-buffer #lock-free #memory #overhead #atomic-ring-buffer #constant-size

atomicring

AtomicRingBuffer是一个固定大小的几乎无锁的并发环形缓冲区

37个版本 (19个稳定版本)

1.2.9 2021年10月30日
1.2.8 2021年3月26日
1.2.7 2020年12月14日
1.2.6 2020年11月7日
0.5.6 2018年5月19日

#273并发

Download history 160/week @ 2024-03-13 234/week @ 2024-03-20 328/week @ 2024-03-27 224/week @ 2024-04-03 249/week @ 2024-04-10 313/week @ 2024-04-17 327/week @ 2024-04-24 367/week @ 2024-05-01 315/week @ 2024-05-08 441/week @ 2024-05-15 442/week @ 2024-05-22 453/week @ 2024-05-29 271/week @ 2024-06-05 200/week @ 2024-06-12 184/week @ 2024-06-19 191/week @ 2024-06-26

每月下载量940

MIT/Apache

60KB
815

AtomicRingBuffer / AtomicRingQueue

Build Status License Cargo Documentation

一个固定大小的几乎无锁的并发环形缓冲区

优点

  • 快速,try_push 和 try_pop 是 O(1)
  • 即使在重并发期间也能很好地扩展
  • AtomicRingBuffer 只有 4 个字的内存开销(AtomicRingQueue 有 6 个字的开销)
  • 通过 AtomicRingQueue 支持阻塞弹出
  • 初始创建后不再进行内存分配

缺点

  • 不支持增长/缩小
  • 最大容量为 (usize >> 16) 个条目
  • 容量向上舍入到下一个2的幂

这个队列的性能应该与 mpmc 类似,但内存开销更低。如果您不关注内存开销,应运行基准测试以决定使用哪个。

实现细节

这个实现使用两个原子操作来存储 read_index/write_index

 Read index atomic
+63------------------------------------------------16+15-----8+7------0+
|                     read_index                     | r_done | r_pend |
+----------------------------------------------------+--------+--------+
 Write index atomic
+63------------------------------------------------16+15-----8+7------0+
|                     write_index                    | w_done | w_pend |
+----------------------------------------------------+--------+--------+
  • write_index/read_index (32位架构上的16位,64位架构上的48位):环形缓冲区中当前读/写位置(头和尾)。
  • r_pend/w_pend (8位):挂起的并发读/写次数
  • r_done/w_done (8位):完成的读/写次数。

读取时,首先增加 r_pend,然后从内存中读取环形缓冲区的内容。读取完成后,增加 r_done。只有当 r_done 等于 r_pend 时才增加 read_index。

写入时,首先增加 w_pend,然后更新环形缓冲区的内容。写入完成后,增加 w_done。如果 w_done 等于 w_pend,则两者都设置为0,并增加 write_index。

在罕见的情况下,这可能导致多个线程轮流增加 r_pend,而 r_done 永远达不到 r_pend 的竞争。如果 r_pend == 255 或 w_pend == 255,则自旋循环等待它变为 <255 以继续。这在实践中很少发生,这就是为什么它被称为几乎无锁。

结构体

此包提供了不带阻塞弹出支持的 AtomicRingBuffer 和带阻塞弹出支持的 AtomicRingQueue

依赖项

此包依赖于 parking_lot 在 AtomicRingQueue 中提供阻塞支持

使用方法

要使用 AtomicRingBuffer,请将以下内容添加到您的 Cargo.toml

[dependencies]
atomicring = "1.2.9"

并在您的代码中添加类似以下内容


// create an AtomicRingBuffer with capacity of 1024 elements 
let ring = ::atomicring::AtomicRingBuffer::with_capacity(900);

// try_pop removes an element of the buffer and returns None if the buffer is empty
assert_eq!(None, ring.try_pop());
// push_overwrite adds an element to the buffer, overwriting the oldest element if the buffer is full: 
ring.push_overwrite(1);
assert_eq!(Some(1), ring.try_pop());
assert_eq!(None, ring.try_pop());

许可证

根据MIT许可证和Apache许可证(版本2.0)授权。

请参阅LICENSE-MITLICENSE-APACHE获取详细信息。

依赖项

~480–790KB
~13K SLoC