Boost atomic: кольцевой буфер без ожидания с большим объемом данных

Я хочу использовать boost::atomic для кольцевого буфера без ожидания, как описано здесь:

Пример повышения

Мой producer одновременно предоставляет большой объем данных (беззнаковый символ, +- 3000 значений), точно так же, как матрица, которую он будет заполнять построчно. Каков наилучший способ push этих значений в буфере? Должен ли я просто перебирать их или я могу как-то memcpy их внутри?

То же самое касается pop, если я хочу прочитать кучу значений одновременно...


Вот что я придумал, по какой причине это не должно быть хорошо? Мне просто нужно убедиться, что RINGBUFFERSIZE % iSize = 0.

#define RINGBUFFERSIZE = 30000

ring_[RINGBUFFERSIZE];

bool push(unsigned char* iData, int iSize)
{
    size_t head = head_.load(boost::memory_order_relaxed);
    size_t next_head = next(head,iSize);
    if (next_head == tail_.load(boost::memory_order_acquire))
    return false;
    memcpy(ring_+head,iData,iSize);
    head_.store(next_head, boost::memory_order_release);
}

bool pop(unsigned char * value, int iSize)
{
     size_t tail = tail_.load(boost::memory_order_relaxed);
     if (tail == head_.load(boost::memory_order_acquire))
         return false;
     value = &ring_[tail];
     tail_.store(next(tail,iSize), boost::memory_order_release);
     return true;
}


size_t next(size_t current, int iSize)
{
     return (current + iSize) % RINGBUFFERSIZE;
}

person Smash    schedule 31.05.2013    source источник
comment
Предложенное решение не совсем работает, потому что next_head могло завернуться. В этом случае у вас нет непрерывного блока и вы не можете выполнить один memcpy (конечно, вы можете проверить этот случай и, возможно, сделать два).   -  person Useless    schedule 01.06.2013


Ответы (1)


Самый быстрый способ - нажать указатель (либо unsigned char *, либо указатель на некоторую структуру, которая также содержит длину).

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


Простой пример решения для управления вашими чанками:

  1. предварительно выделить «достаточно» объектов фрагментов фиксированного размера (скажем, динамическую длину + unsigned char data[3096] или что-то еще)
  2. отправить адрес чанка в кольцевой буфер без ожидания
  3. отправить адрес назад в другой кольцевой буфер, когда потребитель закончит с ним, чтобы производитель мог повторно использовать тот же объект фрагмента

Если вы действительно не можете этого сделать, вы можете выбрать максимальный размер для своих фрагментов и помещать/извлекать объекты этого размера по значению... но, честно говоря, это кажется очень расточительным (даже если объект знает свое длина, поэтому не нужно memcpy весь массив 3k для меньших кусков).

person Useless    schedule 31.05.2013
comment
Точно, указанная память больше не будет действительной, поэтому мне нужно скопировать сами данные. - person Smash; 31.05.2013
comment
Наверняка вы контролируете действительность своих буферов? - person Useless; 31.05.2013
comment
Данные поступают из tcp-соединения, поэтому мне нужно сохранять их при каждом чтении. - person Smash; 31.05.2013
comment
Да, но распределение и управление временем жизни памяти, в которую вы читаете, находится под вашим контролем... если вы не заботитесь конкретно о повторной сборке частичных чтений? - person Useless; 31.05.2013
comment
Вы, конечно, можете это сделать, но я не думаю, что это будет легко сделать с этим контейнером (который ориентирован на объекты с дискретными значениями, а не на потоки данных переменной длины) - person Useless; 31.05.2013
comment
Отсюда вопрос, размещенный здесь, на SO;), но пока спасибо за помощь. +1 - person Smash; 31.05.2013
comment
Возможно, вы могли бы отредактировать дополнительную информацию о том, как выглядят ваши данные и как вы их анализируете/используете, в свой вопрос? - person Useless; 31.05.2013