C ++ Producer消费者队列具有(非常)快速和可靠的切换

时间:2011-08-05 15:47:18

标签: c++ multithreading performance producer-consumer

您好我正在研究使用快速可靠的生产者消费者队列进行线程切换。我正在使用VC ++在Windows上工作。

我的设计基于Anthony Williams队列,也就是说,基本上是一个带有boost :: condition_variable的boost :: mutex。现在通常,notify_one()和唤醒之间的时间在10(罕见)和100微秒之间变化,大多数值在50微秒的范围内。但是,1000中大约有1个超过1毫秒,有些时间超过5毫秒。

我只是想知道这些是否是典型值?是否有更快的信号传递方式?是从这里到管理线程优先级吗?我还没有开始玩优先考虑的问题,但我只是想知道是否有机会将它变成一个大约10微秒的相当稳定的区域?

由于

编辑:使用SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS),平均唤醒时间仍约为50微秒,但异常值较少,现在大多数都在150-200微米左右。除了7毫秒的怪异异常值。嗯...不好。

3 个答案:

答案 0 :(得分:2)

缓解锁定和线程唤醒开销的一种方法是添加第二个队列并实现双缓冲方法。这样就可以在消费者方面进行批处理:

template<typename F>
std::size_t consume_all(F&& f)
{   
    // minimize the scope of the lock
    {
        std::lock_guard<std::mutex> lock(the_mutex);
        std::swap(the_queue, the_queue2);
    }

    // process all items from the_queue2 in batch
    for (auto& item : the_queue2)
    {
        f(item);
    }

    auto result = the_queue2.size();        
    the_queue2.clear(); // clears the queue and preserves the memory. perfect!
    return result;
}

Working sample code.

这不能解决延迟问题,但可以提高吞吐量。如果发生打嗝,则将向消费者呈现大批量,然后可以全速处理,而没有任何锁定开销。这使消费者能够快速赶上制片人。

答案 1 :(得分:1)

有很多事情可能会导致问题。

您可能需要尝试对应用进行分析,并查看可能发生减速的位置。

一些注意事项:

  • 消费者和生产者是否在同一个过程中?如果是这样,Critical Section比Mutex快得多。
  • 尝试确保所有队列内存都在当前内存中。如果你必须交换会减慢速度的页面。
  • 要非常小心地将流程设置为实时优先级。这应该是系统进程。如果该过程做了太多工作,它可以防止关键系统进程获得cpu,这可能会非常糟糕。除非你绝对需要实时,否则只需使用HIGH_PRIORITY_CLASS

答案 2 :(得分:1)

简短的回答是肯定的,从那里它真正归结为操作系统管理和线程调度。 RTS(实时系统)可以将这50个微处理器带到大约15微处理器,更重要的是,它们可以摆脱异常值。否则旋转是唯一的答案。如果有多个队列而不是核心,那么想法可能是让x个线程旋转,立即做出反应,以及剩下的阻塞。这将涉及某种“主”队列线程,不断旋转以检查所有队列,并且 - 处理项本身 - 或将它们交给工作线程,其中一些也可以旋转以保存那50个微处理器。但这很复杂。

可能最好只使用一个带有旋转消费者线程的单个无锁多生产者单一消费者队列。然后,进入队列的所有项目可能需要从公共基本类型派生,并且需要包含一些关于如何处理项目的元信息。

复杂但可能。如果我设置了它,我也可以发布一些代码。