Smash
Smash

Reputation: 3802

Boost atomic: wait-free ring buffer with large amount of data

I want to use boost::atomic for a wait-free ring buffer as described here:

Boost Example

My producer provides large amount of data at the same time (unsigned char, +- 3000 values), just like a matrix it would fill line by line. What is the best way to push these values in the buffer ? Should I just loop over them or can I memcpy them inside somehow?

Same goes for pop if I want to read a bunch of values at the same time...


Here is what I came up with, any reason this should not be good ? I just need to make sure 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;
}

Upvotes: 1

Views: 1967

Answers (1)

Useless
Useless

Reputation: 67713

The fastest way is to push a pointer (either unsigned char * or pointer to some structure which contains the length as well).

Of course, assuming it's ok to force pop to take exactly the same chunks that were pushed, this just moves the problem: now you have to manage the allocation of these buffers somehow.


Simple sample solution for managing your chunks:

  1. pre-allocate "enough" fixed-size chunk objects (say a dynamic length + unsigned char data[3096] or whatever)
  2. send address of a chunk in your wait-free ring buffer
  3. send address back in another ring buffer when the consumer is done with it, so the producer can recycle the same chunk object

If you really can't do this, you could pick a maximum size for your chunks and push/pop objects of that size by value ... but honestly this seems very wasteful (even if object knows its length so doesn't have to memcpy the whole 3k array for smaller chunks).

Upvotes: 1

Related Questions