2

我今天早些时候发现boost::circular缓冲区的迭代器在多线程环境中的行为并不像我预期的那样。(尽管公平地说,它们的行为也与我在单线程程序中的想法不同)。

如果您调用buffer.begin()buffer.end()表示迭代器以用于循环特定的数据序列。如果将更多数据添加到circular_buffer. end()显然,如果您在数据更改后再次调用,您会期望得到不同的结果。但令人困惑的是您已经更改的迭代器对象的值。

有没有一种方法可以创建迭代器,使您可以处理循环缓冲区中的一组数据范围,并且即使在处理范围时将其他数据添加到缓冲区也不会更改它们的值?

如果没有,是否有可能适用的首选“非迭代器”模式,或者可能允许这样做的不同容器类?

#include "stdafx.h"
#include <boost\thread.hpp>
#include <boost\thread\thread_time.hpp>
#include <boost\circular_buffer.hpp>

int _tmain(int argc, _TCHAR* argv[])
{
    boost::circular_buffer<int> buffer(20);

    buffer.push_back(99);
    buffer.push_back(99);
    buffer.push_back(99);

    boost::circular_buffer<int>::const_iterator itBegin = buffer.begin();
    boost::circular_buffer<int>::const_iterator itEnd = buffer.end();

    int count = itEnd - itBegin;
    printf("itEnd - itBegin == %i\n", count); //prints 3

    /* another thread (or this one) pushes an item*/
    buffer.push_back(99);

    /*we check values of begin and end again, they've changed, even though we have not done anything in this thread*/
    count = itEnd - itBegin;
    printf("itEnd - itBegin == %i\n", count); //prints 4 
}

更新以获取对 ronag 的更详细响应我正在寻找生产者消费者类型模型,并且 boost 文档中显示的有界缓冲区示例与我所需要的非常接近。除了以下两个例外。

  1. 我需要能够一次从缓冲区中读取多个数据元素,检查它们,这可能不是微不足道的,然后选择要从缓冲区中删除多少项目。

    假的例子:试图从一个字符串中处理两个单词 hello 和 world。

    读取 1,缓冲区包含 hel,不要从缓冲区中删除字符。-more 产生读取 2,缓冲区包含 hellowo,我发现 'hello' 删除 5 个字符,缓冲区现在有 wo -more 产生读取 3,缓冲区包含 world,处理 'world',删除另外 5 个字符。

  2. 读取时我不需要阻塞生产者线程,除非缓冲区已满。

4

2 回答 2

2

根据boost::circular_buffer::iterator docs,您的迭代器应该保持有效。(当同时变异和迭代容器时,我总是首先检查。)所以你的示例代码是合法的。

发生的事情是由于 STL 迭代器约定:end()不指向元素,而是指向虚构的最后一个元素。在第四个之后push_back,从itBegin(第一个元素)到itEnd(一个过去的最后一个元素)的距离增加了。

一种解决方案可能是持有一个指向具体元素的迭代器,例如

itPenultimate = itEnd - 1;

itBegin现在,即使循环缓冲区被扩展,从to的距离也itPenultimate将保持不变,只要它不在范围内。

于 2011-11-23T21:03:36.627 回答
1

该文档明确指出循环缓冲区不是线程安全的,并且用户负责锁定数据结构。那将解决您的问题。

但也许生产者-消费者风格的队列更适合您的问题。

于 2011-11-23T20:54:33.683 回答