【问题标题】:boost c++ lock-free queue vs shared queueboost c++ 无锁队列与共享队列
【发布时间】:2013-04-22 21:51:19
【问题描述】:

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

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

【问题讨论】:

  • 主要看你是否为多核处理器编程。如果您的目标处理器是单核,那么您应该使用 shared_queue。
  • 目标机器是2核4线程。好的,我会尝试 boost::lockfree。
  • 我认为无锁队列即使在单核处理器中也有一席之地。例如,如果您有一个在任何情况下都不应该被阻塞的实时线程,并且如果它需要将数据传递给另一个线程(例如,“空闲任务”线程),那么无锁队列将是一个不错的解决方案。

标签: c++ multithreading boost producer-consumer lock-free


【解决方案1】:

在您的应用中尝试两者,看看哪个效果最好。

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

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

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

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

【讨论】:

    【解决方案2】:

    (补充)

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

    boost::lockfree::queue

    • T 必须有一个拷贝构造函数
    • T 必须有一个平凡的赋值运算符
    • T 必须有一个普通的析构函数

    boost::lockfree::stack

    • T 必须有一个拷贝构造函数

    boost::lockfree::spsc_queue

    • T 必须有一个默认构造函数
    • T 必须是可复制的

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        决定归结为提出以下问题:“锁竞争会成为待解决任务的问题吗?”

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

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

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

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

        【讨论】:

          猜你喜欢
          • 2017-04-21
          • 1970-01-01
          • 2011-08-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多