试图了解boost队列示例

时间:2016-03-29 20:17:44

标签: c++ multithreading boost queue

我试图了解来自boost.org的队列示例。特别是最简单的单生产者单个消费者队列。请考虑以下代码。

为什么consumer_count是原子而不是producer_count?他们都在自己的线程中改变。

在声明队列的行上为什么尖括号中有一个常量?我在构造foo<bar>中认为,bar只是foo的修饰符,如Vector<double>。我知道它设置了队列的大小,但是为什么尖括号而不是像正常函数调用的括号一样?

查看producer中for循环中的空while循环。如果队列填满,则push函数返回false。那么这不会进入无限循环吗?

我不理解无锁概念。什么是锁?

为什么消费者中有2个pop循环?

如果生产者&amp;消费者同时以相同的优先级运行,队列的大小应该在0或1附近徘徊?或者它是否填充然后转储和&amp;结束了吗?

在连接使用者线程之前,在main中设置了Done。我很困惑。这段代码结尾附近的事件顺序是什么?

#include <boost/thread/thread.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <iostream>
#include <boost/atomic.hpp>
int producer_count = 0;
boost::atomic_int consumer_count (0);
boost::lockfree::spsc_queue<int, boost::lockfree::capacity<1024> > spsc_queue;
const int iterations = 10000000;
void producer(void)
{
    for (int i = 0; i != iterations; ++i) {
        int value = ++producer_count;
        while (!spsc_queue.push(value));
    }
}
boost::atomic<bool> done (false);
void consumer(void)
{
    int value;
    while (!done) {
        while (spsc_queue.pop(value)) ++consumer_count;
    }

    while (spsc_queue.pop(value)) ++consumer_count;
}
int main(int argc, char* argv[]) {
    using namespace std;
    cout << "boost::lockfree::queue is ";
    if (!spsc_queue.is_lock_free()) cout << "not ";
    cout << "lockfree" << endl;

    boost::thread producer_thread(producer);
    boost::thread consumer_thread(consumer);

    producer_thread.join();
    done = true;
    consumer_thread.join();

    cout << "produced " << producer_count << " objects." << endl;
    cout << "consumed " << consumer_count << " objects." << endl;
}

1 个答案:

答案 0 :(得分:2)

单一生产者,单一消费者说这一切:它具有原子性,因为所有写入恰好发生在一个线程上,并且所有写入恰好在另一个线程上。这是合同

由于内存排序¹,合同让位于大量优化。

  

为什么consumer_count是原子而不是producer_count?他们都在自己的线索内改变。

不确定。考虑询问样本的作者.²

  

在声明队列的行上为什么尖括号中有一个常量?我认为在构造foo中,bar只是foo的修饰符,就像Vector一样。我知道它正在设置队列的大小,但为什么尖括号而不是像正常函数调用的括号?

环形缓冲区具有静态容量。它位于尖括号中,因为它是模板参数,而不是函数参数。静态地做事情为编译器提供了更多的知识,可以在编译时进行优化。

无论目标如何,决定制作静态和动态的是API设计选择。

  

查看producer中for循环中的空while循环。如果队列填满,则push函数返回false。那么这不会进入无限循环吗?

是。这在无锁处理中是正常的。替代方案是......阻止直到情况得到解决,但这会引入:锁定。锁具有更高的延迟开销。因此,可以优先考虑繁忙循环的成本,以支持尽可能低的延迟。

  

我不懂锁定概念。什么是锁?

见我上一段。因此,在单核系统上无锁是没有意义的。在每个线程可以在专用CPU核心上运行的系统中最有意义,任务通常只需要很少的时间,低延迟比能源效率更重要,并且没有后台进程干扰最佳CPU利用率。

  

为什么消费者中有2个pop循环?

第一次运行直到重置done。如果有剩余的元素,第二个会排空队列。

  

如果生产者&amp;消费者同时以相同的优先级运行,队列的大小应该在0或1附近徘徊?或者它是否填充然后转储和&amp;结束了吗?

这取决于时间,因此是未定义的:它取决于CPU架构,系统负载,流水线效率,缓存失效等。是的,考虑到消费者/生产者基本上都是无操作循环,您可能期望系统是能够获得一些“稳定”的加载节奏,其中队列平均n个项目。

  

在连接使用者线程之前,在main中设置了Done。我糊涂了。这段代码结尾附近的事件顺序是什么?

生产者一直运行到完成。该主题是主要的。完成重置。第一个消费者循环退出。如果有更多剩余元素排队,则第二个消费者循环会消耗它们。消费者线程结束。该主题在main中加入。

¹具体来说,消费者中的memory_order acquire和生产者中的release,但这些是您不必担心的实施细节,只要您满足使用要求