试图理解提升队列示例

trying to understand boost queue examples

本文关键字:队列      更新时间:2023-10-16

我试图理解boost.org中的队列示例。特别是最简单的单生产者-单消费者队列。请考虑下面的代码。

为什么consumer_count是原子的而不是生产者_count?它们都在各自的线程中发生变化。

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

查看生产者中for循环中的空while循环。如果队列已满,那么push函数将返回false。难道这会进入一个无限循环吗?

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

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

如果生产者&消费者以相同的优先级同时运行队列的大小应该徘徊在0或1附近,对吗?或者它填充然后倾倒&结束

在联接使用者线程之前,在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;
}

单一生产者,单一消费者说了一切:只要所有写入都发生在一个线程上,所有读取都发生在另一个线程,它就具有原子性。这是合同

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

为什么consumer_count是原子的而不是生产者_count?它们都在各自的线程中发生变化。

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

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

环形缓冲区具有静态容量。它在尖括号中,因为它是一个模板参数,而不是函数参数。再次以静态方式进行操作会为编译器提供更多的知识,以便在编译时进行优化。

不管目标是什么,决定什么是静态的和动态的是API的设计选择。

查看生产者中for循环中的空while循环。如果队列已满,那么push函数将返回false。难道这会进入一个无限循环吗?

是的。这在无锁定处理中是正常的。另一种选择是……阻止,直到情况得到解决,但这会引入:锁定。锁的延迟开销要高得多。因此,繁忙循环的成本可以优先考虑尽可能低的延迟。

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

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

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

第一次运行直到done被重置。第二个耗尽队列,以防存在剩余元素。

如果生产者&消费者以相同的优先级同时运行队列的大小应该徘徊在0或1附近,对吗?或者它填充然后倾倒&结束

这取决于时间,因此是未定义的:它取决于CPU架构、系统负载、管道效率、缓存无效等。是的,考虑到消费者/生产者基本上都是无所事事的循环,您可能希望系统能够获得一些"稳定"的加载节奏,其中队列平均为n项。

在联接使用者线程之前,在main中设置Done。我很困惑。此代码末尾的事件顺序是什么?

生产商一直运行到完工。那根线主要是连在一起的。完成即重置。第一个使用者循环退出。如果队列中还有更多剩余元素,则第二个使用者循环会消耗它们。消费者线程结束。那根线主要是连在一起的。


特别是消费者中的memory_order acquire和生产者中的release,但只要满足使用要求,这些都是不需要担心的实现细节。