我目前正在尝试思考如何安全地处理循环缓冲区已满并且生产者想要将数据插入其中的情况。 原因是我遇到了一个典型的生产者-消费者问题,相机(生产者)生成图像,查看器(消费者)显示图像,两者都在自己的线程中运行。由于我不想限制相机的帧速率(也许这不是最好的主意,但我们假设它是),生产者可能会在某些时候覆盖消费者尚未处理的图像。 由于图像可能相当大,我会选择不按值返回它们,而是按引用或指针返回它们。因此,一旦缓冲区已满,生产者可能会覆盖消费者当前持有的指针的图像,甚至可能在消费者读取其内存位置时也是如此。当然,这是一种需要避免的行为,因为消费者不希望数据在他的手指下改变。
但是,我想知道人们真正期望的行为是什么,以及哪种解决方案是最好的、最封装的解决方案。
由于不希望限制相机帧速率,因此一旦尝试覆盖活动图像,就不能简单地使用互斥体或信号量来暂停生成器。因此,我在这里能想到的唯一解决方案是跳过消费者当前处理的图像并覆盖第二旧的图像。然而,为此需要一种机制来指示当前正在使用该图像。也许在请求图像时返回
std::shared_ptr
并在覆盖图像时检查其 use_count
是一种选择。
我试图找到类似的问题,但找不到。任何如何正确解决这个问题的输入,或者如果这个问题不是问题,因为我的基本想法有缺陷,都会有所帮助。非常感谢!
我认为放弃真正的循环缓冲区的想法是最容易的。循环缓冲区的主要动机是它们是表示小记录的大队列的最有效方式,因为没有每条记录的内存开销。这是由非常小的元素组成的有用队列(例如,具有 16 或 32 位样本的音频缓冲区),但正如您所发现的,它不能很好地支持您的用例。
在您的示例中,队列条目(包含视频帧的缓冲区)可能非常大(如果不是兆字节,也是千字节?),因此您不妨将它们分配在堆上,并将指向缓冲区的指针放入简单的类似队列的数据中结构。
对于您的问题,只要有:
然后消费者会做类似的事情:
制作人:
列表可以是简单的`std::deque
请注意,如果需要,您仍然可以在连续内存中分配所有缓冲区。重要的是,您只将指针存储在队列中,以便同步访问可以非常快。