c++ - 真正无锁 MPMC 环形缓冲区?线程能够互相协助以避免阻塞吗?

标签 c++ multithreading algorithm lock-free

这个问题的灵感来自 Lock-free Progress Guarantees 。显示的代码并不是严格无锁的。每当写入线程在队列不为空或未满时挂起时,读取线程都会返回 false,从而阻止整个数据结构取得进展。
真正无锁环形缓冲区的正确行为应该是什么?

Generally, truly lock-free algorithms involve a phase where a pre-empted thread actually tries to ASSIST the other thread in completing an operation.

有关于此技术的引用吗?如何针对基于数组的 MPMC 队列实现它?

我查看了一些代码,它们也有类似的问题。

最佳答案

作为跨线程辅助如何在现实生活中最终发挥作用的一个很好的例子,考虑可以通过更改 liblfds 来获得无锁 MPMC 队列。算法大致如下:

使用 3 个计数器:

  • alloc_pos :已启动的推送操作总数。当推送开始时,该值会自动递增。
  • write_pos :已知较低位置的所有写入操作均已完成。
  • read_pos :所有写在较低位置的元素都已被消耗。

在此方案中,推送或弹出操作由受影响插槽中的 CAS 完成。 write_posread_pos变量是多余的。

因此,要推送,线程首先递增 alloc_pos ,然后递增 write_pos过去它前面所有能看到的槽位都已完成。这是一个辅助——它正在完成之前在其他线程中启动的写入。然后线程必须扫描 write_pos 之间的槽。和alloc_pos直到它找到一个空闲的并设法通过 CAS 保留它。

要弹出,读取器首先递增 read_pos过去它可以看到的所有写在较低位置的项目都被消耗掉了。这又是一个帮助——完成之前的阅读。然后它从read_pos开始扫描至alloc_pos查看是否可以找到已完成写入的项目。

正如评论中提到的,真正做到这一点会很烦人,因为实现决策会权衡性能与您需要的排序和可用性保证,以及跳过障碍以防止 ABA 问题。

关于c++ - 真正无锁 MPMC 环形缓冲区?线程能够互相协助以避免阻塞吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71725753/

相关文章:

c++ - 什么是 operator class_name() 常量?

java - 可以将 'this' 传递给 ScheduledExecutorService.scheduleWithFixedDelay() 吗?

android - 无法修复 Android 中的 future 任务异常

multithreading - 线程中的 Delphi DragDrop 组件

algorithm - Big-O 和 Big-theta 可以互换使用吗?

algorithm - 使用 BFS 找到三角形中的 Fermat 点

c++ - 通过 if 语句需要左值作为赋值错误的左操作数

c++ - 具有通用引用的成员函数模板不接受左值

algorithm - 如何生成仅包含 2 种数字的第 n 个数字?

c++ - 如何在 vector C++ 中打印元素