使用STL向量作为字节数据的FIFO容器

时间:2017-01-18 17:17:22

标签: c++ performance vector stl

我有一个运行的线程从串口读取字节流。它在后台持续执行此操作,并且从流中读取的内容分别在不同的时间进行。我将数据存储在一个容器中,如下所示:

using ByteVector = std::vector<std::uint8_t>;
ByteVector receive_queue;

当数据从串口进入时,我将它附加到字节队列的末尾:

ByteVector read_bytes = serial_port->ReadBytes(100); // read 100 bytes; returns as a "ByteVector"
receive_queue.insert(receive_queue.end(), read_bytes.begin(), read_bytes.end());

当我准备好读取接收队列中的数据时,我将其从前面删除:

unsigned read_bytes = 100;
// Read 100 bytes from the front of the vector by using indices or iterators, then:
receive_queue.erase(receive_queue.begin(), receive_queue.begin() + read_bytes);

这不是完整的代码,但是我很好地了解了如何利用该向量来实现这种数据流机制。

我对此实现的主要关注是从前面移除,这需要移除每个元素(我不确定向量的优化erase()如何,但在最坏的情况下,每个元素移除导致整个矢量的移位)。另一方面,由于数据的连续性,向量是CPU缓存局部性的候选者(但不保证CPU缓存的使用)。

我想过可能会使用boost::circular_buffer,但我不确定它是否适合这项工作。

我尚未为接收队列的增长编写上限,但我可以在某处轻松地执行reserve(MAX_RECEIVE_BYTES),并确保size()永远不会超过MAX_RECEIVE_BYTES因为我继续追加它的背面。

这种方法一般都可以吗?如果没有,那有什么性能问题?什么容器在这里更合适?

2 个答案:

答案 0 :(得分:5)

从向量的前面擦除a当时元素可能非常慢,特别是如果缓冲区很大(除非你可以重新排序元素,你不能使用FIFO队列)。

循环缓冲区对于固定大小的FIFO队列来说是一种很好的,也许是理想的数据结构。但是标准库中没有实现。您必须自己实施或使用第三方实施,例如您发现的Boost。

标准库为不断增长的FIFO队列提供了高级结构:std::queue。对于较低级别的数据结构,双端队列是一个不错的选择(std::deque,它是std::queue的默认底层容器。)

  

另一方面,由于数据的连续性,向量是CPU缓存局部性的候选者(但这不能得到保证)。

保证std::vector的连续存储。固定的循环缓冲区也有连续存储。

我不确定std::deque的缓存局部性有什么保证,但在实践中它通常非常好,因为典型的实现是数组的链接列表。

答案 1 :(得分:0)

表现差,可能或不重要。从头部开始需要一连串的动作。但STL正是为了这个目的排队,只需使用一个。