c++ - 避免在单一生产者单一消费者程序中忙于等待,即使用 spsc_queue

原文 标签 c++ multithreading boost

我正在尝试实现单个生产者(主线程)和单个消费者(从主线程产生的子线程)问题,因此根据我的搜索,我得到了 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 - 有人可以帮我找出避免忙碌等待的最佳方法吗?

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

最佳答案

您的目标与您的要求不兼容。

免等待:等到一个元素可用已经排除了这个属性。

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

你真正想要的是

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

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

也许最接近你想要的是:
if (spsc_queue.empty()) {
    std::this_thread::yield();
}

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

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

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

关于c++ - 避免在单一生产者单一消费者程序中忙于等待,即使用 spsc_queue,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32568777/

相关文章:

objective-c - 锁定一个对象不被多个线程访问 - Objective-C

c++ - 不能在非 Boost 版本的 Asio 中使用 asio::placeholders::error

c++ - 实现循环缓冲区以在一次调用中写入/读取任意数量的数据

c++ - C++ 抽象工厂是否应该为构造对象提供销毁方法?

c++ - 优先获取互斥体以提高流程

sql-server - SQL数据库触发器线程安全吗?

c++ - C++中的MongoDB $ group命令

Android - 如何避免两个 runOnUIThread 调用之间的死锁

c++ - 通过两次连续调用 boost::asio::read 检索正确数据

C++ 是否有任何线程安全可以写入(比没有锁的线程安全类似物更快)组件?