Итераторы, значение результата вызова end () изменяется по мере добавления данных в циркулярный_буфер - PullRequest
2 голосов
/ 24 ноября 2011

Сегодня я обнаружил, что итераторы буфера 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 
}

Обновление для более подробного ответа на Ронаг Я ищу модель потребительского типа производителя, и пример ограниченного буфера, показанный в документации наддува, ЗАКРЫТ на то, что мне нужно. со следующими двумя исключениями.

  1. Мне нужно иметь возможность считывать более одного элемента данных из буфера одновременно, проверять их, что может быть нетривиальным, а затем выбирать, сколько элементов следует удалить из буфера.

    поддельный пример: попытка обработать два слова hello & world из цепочки символов.

    чтение 1, буфер содержит h-e-l, не удаляйте символы из буфера. -производство чтение 2, буфер содержит h-e-l-l-o-w-o, я нашел «привет», удалил 5 символов, буфер теперь имеет w-o -производство чтение 3, буфер содержит w-o-r-l-d, процесс 'world', удалите еще 5 символов.

  2. Мне не нужно блокировать поток производителя при чтении, если буфер не заполнен.

Ответы [ 2 ]

2 голосов
/ 24 ноября 2011

Согласно документам boost :: циркуляр_буффер :: итератор , ваши итераторы должны оставаться действительными.(Всегда первое, что я проверяю, когда изменяю и повторяю контейнер одновременно.) Так что ваш пример кода допустим.

То, что происходит, происходит из-за соглашения итератора STL: end() не указываетэлемент, а скорее к воображаемому элементу «один за последним».После четвертого push_back расстояние от itBegin (первый элемент) до itEnd (один элемент после последнего) увеличилось.

Одним из решений может быть удержание итератора, указывающегодо конкретного элемента, например

itPenultimate = itEnd - 1;

Теперь расстояние от itBegin до itPenultimate останется неизменным даже при расширении циклического буфера, пока он не находится в диапазоне.

1 голос
/ 24 ноября 2011

В документе четко указано, что циклический буфер не является поточно-ориентированным и что пользователь отвечает за блокировку структуры данных. Это решило бы вашу проблему.

Но, возможно, очередь в стиле производитель-потребитель лучше подходит для вашей проблемы.

...