13

我是多线程编程的新手,我只知道最常见的 Producer-Consumer-Queue。我正在使用 boost c++ 库,我不知道是否更好地使用 boost::lockfree::queue 或使用`mutex`和`condition_variable`的std::queue 周围的包装类。

使用无锁数据结构哪里更好,哪里更好使用基于 `mutex` 和 `condition_variables` 的简单实现?

4

4 回答 4

22

在您的应用程序中尝试这两种方法,看看哪个效果最好。

通常,当队列几乎总是有条目时,轮询无锁队列效果最好,当队列几乎总是空时,阻塞队列效果最好。

阻塞队列的缺点是延迟,通常为 2-20 uS,这是由于内核信号。这可以通过设计系统来缓解,使消费者线程在每个排队项目上完成的工作花费的时间比这个间隔长得多。

非阻塞队列的缺点是在轮询空队列时会浪费 CPU 和内存带宽。这可以通过设计系统使队列很少为空来缓解。

正如评论者已经暗示的那样,非阻塞队列在单 CPU 系统上是一个非常糟糕的主意。

于 2013-04-29T10:27:20.350 回答
10

(补充)

从 1.54 开始,您应该了解一些要求

boost::lockfree::queue

  • T 必须有一个复制构造函数
  • T 必须有一个平凡的赋值运算符
  • T 必须有一个简单的析构函数

boost::lockfree::stack

  • T 必须有一个复制构造函数

boost::lockfree::spsc_queue

  • T 必须有一个默认构造函数
  • T 必须是可复制的
于 2013-07-16T16:47:44.623 回答
4

您还可以使用无锁队列来避免实时应用程序中的优先级反转。

例如,Android 上的 OpenSL 在高优先级线程上提供音频缓冲区队列回调。如果该线程必须等待较低优先级线程持有的锁,那么它的高优先级调度将毫无意义,回调变得不规则,并且您可能会开始欠载音频缓冲区——这会导致一些令人不快的爆裂声。

于 2014-04-08T21:05:48.687 回答
2

该决定归结为提出一个问题:“锁定争用是否会成为待解决任务的问题?”

锁定在并发环境中解决了两个不同的问题

  • 正确性:确保代码确实按照预期进行。防止来自其他线程的干扰。
  • 吞吐量/可扩展性:允许通过系统的并发操作的持续高“流”。允许通过添加更多资源来扩展系统的性能。

这两个问题是对立的目标。经典方法是使用全局锁保护共享数据结构。这确保了 100% 的正确性,但它阻止了性能的扩展,尤其是并发级别超过一定程度,因为共享锁会导致“流量拥塞”

顺便说一句,在使用“无锁”一词时需要小心。严格来说,协同操作永远不可能100%无锁。但是可以巧妙地安排协作,从而减少阻塞对那些真正需要同时访问同一元素的合作伙伴的影响。

于 2014-03-07T16:55:19.643 回答