迭代器,调用 end() 的结果值随着数据添加到circular_buffer而变化
今天早些时候,我发现 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 文档中显示的有界缓冲区示例非常接近我所需要的。但以下两个例外。
我需要能够一次从缓冲区读取多个数据元素,检查它们(这可能不是一件小事),然后选择要从缓冲区中删除的项目数。
假示例:尝试处理两个单词 hello &由一串字符组成的世界。
读取1,缓冲区包含hel,不要从缓冲区中删除字符。 -更多生产 读2,缓冲区包含hellowo,我发现'hello'删除了5个字符,缓冲区现在有wo -更多生产 读取 3,缓冲区包含世界,处理“世界”,删除另外 5 个字符。
读取时我不需要阻塞生产者线程,除非缓冲区已满。
I discovered earlier today that the iterators of a boost::circular
buffer were not behaving quite as I expected them to in a multi-threaded environment. (although to be fair they behave differently than I would think in a single threaded program too).
if you make calls to buffer.begin()
and buffer.end()
to represent iterators to use to loop over a specific seqment of data. The value of the end iterator changes if more data is added to the circular_buffer
. Obviously you would expect to get a different result if you made another call to end()
after the data was changed. But what is confusing is the value of the iterator object you already made changing.
Is there a way to create iterators that allow you to work on a set range of data in a circular_buffer and do not have their values changed even if additional data is added to the buffer while working on a range?
If not, is there a preferred 'non-iterator' pattern that might apply, or a different container class that might allow this?
#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
}
Update for more detailed response to ronag
I am looking for a producer consumer type model, and the bounded buffer example shown in the boost documentation is CLOSE to what I need. with the following two exceptions.
I need to be able to read more than one element of data off the buffer at a time, inspect them, which may not be trivial, and then choose how many items to to remove from the buffer.
fake example: trying to process the two words hello & world from a string of characters.
read 1, buffer contains h-e-l, do not remove chars from the buffer.
-more producing
read 2, buffer contains h-e-l-l-o-w-o, I found 'hello' remove 5 chars, buffer now has w-o
-more producing
read 3, buffer contains w-o-r-l-d, process 'world', remove another 5 characters.I need to not block the producer thread when reading, unless the buffer is full.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
根据 boost::circular_buffer::iterator 文档,你的迭代器应该保持有效。 (同时修改和迭代容器时,我总是首先检查。)所以您的示例代码是合法的。
发生的情况是由于 STL 迭代器约定所致:
end()
并不指向某个元素,而是指向虚构的最后一个元素。在第四个push_back
之后,从itBegin
(第一个元素)到itEnd
(最后一个元素)的距离增加了。一种解决方案可能是持有一个指向具体元素的迭代器,例如
现在,即使循环缓冲区扩展,从
itBegin
到itPenultimate
的距离也将保持不变,只要因为它不在范围内。According to the boost::circular_buffer::iterator docs, your iterators should remain valid. (Always the first thing I check when mutating and iterating a container at the same time.) So your example code is legal.
What is happening is due to STL iterator convention:
end()
doesn't point at an element, but rather to the imaginary one-past-the-last element. After the fourthpush_back
, the distance fromitBegin
(the first element) toitEnd
(one-past-the-last element) has increased.One solution may be to hold an iterator pointing to a concrete element, e.g.
Now the distance from
itBegin
toitPenultimate
will remain the same even when the circular buffer is extended, as long as it's not in the range.该文档明确指出循环缓冲区 不是线程安全并且用户负责锁定数据结构。那可以解决你的问题。
但也许生产者-消费者风格的队列更适合您的问题。
The doc explicitly states that circular buffer is not thread-safe and that the user is responsible for locking the data structure. That would remedy your problem.
But maybe a producer-consumer style queue is better suited for your problem.