迭代器,调用 end() 的结果值随着数据添加到circular_buffer而变化

发布于 2024-12-18 00:00:52 字数 1657 浏览 3 评论 0原文

今天早些时候,我发现 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 &由一串字符组成的世界。

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

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

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.

  1. 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.

  2. I need to not block the producer thread when reading, unless the buffer is full.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

刘备忘录 2024-12-25 00:00:52

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

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

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

itPenultimate = itEnd - 1;

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

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 fourth push_back, the distance from itBegin (the first element) to itEnd (one-past-the-last element) has increased.

One solution may be to hold an iterator pointing to a concrete element, e.g.

itPenultimate = itEnd - 1;

Now the distance from itBegin to itPenultimate will remain the same even when the circular buffer is extended, as long as it's not in the range.

失眠症患者 2024-12-25 00:00:52

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文