【问题标题】:Avoiding busy waiting in a Single Producer Single Consumer Program viz using spsc_queue避免在单一生产者单一消费者程序中忙于等待,即使用 spsc_queue
【发布时间】:2015-09-14 15:42:45
【问题描述】:

我正在尝试实现单个生产者(主线程)和单个消费者(从主线程产生的子线程)问题,因此根据我的搜索,我得到了 spsc_queue 作为 boost 库提供的最佳无锁数据结构。现在从他们的示例代码中获取,消费者函数看起来像这样:

void consumer(void)
{
    int value;
    while (!done) {
        while (queue.pop(value))
            ++consumer_count;
    }

    while (queue.pop(value))
        ++consumer_count;
}

现在,spsc_queue may remain empty for sometime 等可能会发生,为了避免忙等待,我在这样的代码中引入了 sleep:

void consumer(void)
{
    int value;
    while (!done) {
        if (spsc_queue.empty())
        {
            cout << "Waiting for data....\n";
            this_thread::sleep_for (chrono::milliseconds(100));
        }
        else
        {
            while (spsc_queue.pop(value))
            {
                ++consumer_count;
            }
        }
    }

    while (spsc_queue.pop(value))
        ++consumer_count;
}

这是正确的做法吗?或者,有没有更好的方法来做到这一点? 我遇到了一些库,例如 libeventlibevboost::asio::io_service - 有人可以帮我找出避免忙碌等待的最佳方法吗?

我关心的是性能,代码必须是无锁和无等待的(如果可能的话)。任何帮助将不胜感激。

【问题讨论】:

  • 你的问题太狭隘了。如果队列是空的,你应该很高兴你无事可做,可以去做其他活动,而不是忙着等待。
  • 但是假设消费者进入睡眠状态并且就在那一刻之后生产者将数据推送到队列中。在这种情况下,等待 100 毫秒是不可避免的,因为我无法在队列上执行 select() 调用,这会告诉我数据已准备好读取。即使您有数据要阅读,为什么还要浪费时间睡觉。明白我的意思了吗?
  • 这不是一个有用的情况。您需要为无锁队列提供适当的情况。例如,您可以有一个消息传递系统,其中邮件人线程从线程本地队列收集消息,线程通过将消息推送到它们的私有队列来产生消息。然后他们还可以触发 eventfd,并且邮件人线程可以在 eventfd 上进行 epoll。这对于非阻塞队列来说是一种有用的情况,但是您在其他地方(例如在 epoll 中)进行调度/休眠。

标签: c++ multithreading boost


【解决方案1】:

您的目标不符合您的要求。

无需等待:等到元素可用已排除此属性。

无锁:您的目标是在元素可用之前不做任何工作,即您想要阻止。这又与无等待和无锁相矛盾。

你真正想要的是类似的东西

if (spsc_queue.empty()) {
     doSomethingElse();
}

或者简单地说,继续忙循环。

也许最接近你想要的是这个:

if (spsc_queue.empty()) {
    std::this_thread::yield();
}

它重新调度线程并让其他线程完成它们的工作。但是,您放弃了时间片,并且可能不会在 25-100 毫秒之前重新安排。

代码必须无锁的任何具体原因?既然您的队列为空的可能性似乎很高,为什么您需要无锁代码?在这种情况下,你没有任何收获。

另一方面,如果您出现空队列的概率很低,那么繁忙循环会随着时间的推移而摊销。无论如何,您不会在忙碌的循环中花费太多时间,而是尽可能快地取出您的元素(以偶尔的忙碌等待为代价)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-24
    • 2015-04-05
    相关资源
    最近更新 更多