试图理解提升队列示例
trying to understand boost queue examples
我试图理解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
,但只要满足使用要求,这些都是不需要担心的实现细节。
- boost::进程间消息队列引发错误
- 如果我只是不访问queue_front节点的子节点,而是将它们推到队列中呢?还是BFS吗
- Android NDK传感器向事件队列报告奇怪的间隔
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 按对象的特定方法按升序排列的C++优先级队列
- 使用2个键的cpp-stl::优先级队列排序不正确
- 我是否需要在下一次转移时将所有权*转移回转移队列
- 在一个读写器队列中,我可以用volatile替换原子吗
- 为什么我的多线程作业队列崩溃
- 尝试将lambda函数放在队列中时出现一般分配器错误(可能是与unique_ptr有关的错误)
- 使用"Task"函数指针队列定义作业管理器
- 在c++队列中使用pop和visit实现线程安全
- 为什么我需要C++中不同的排序格式来对这个USACO代码上的数组和优先级队列进行排序
- 打印优先级队列
- 共享队列的线程安全
- 带自定义比较器的最小优先级队列
- 在 Vulkan Qt 中获取队列系列
- 堆栈和队列是否像C++中的数组一样传递?
- 在C++中创建队列 - 什么是 malloc 错误?
- 优先级队列自定义比较器