I have implemented my own lock-free ringbuffer for multiple producers multiple consumers using vector. Can you guys help me review to see if there are any problems and ways to improve?
Explanation:
Each producer runs on its own thread and will use Push()
to enter its item into the RingBuffer
.
Each consumer runs on its own thread and has its own unique number. When consumer TryRead()
, it will enter its unique number.
RingBuffer
will keep track of the last position each consumer read in std::vector<long> mReadIdxVec
If mReadIdxVec[consumer unique number] >= mMaxReadIdx
, TryRead()
will return a nullptr
.
Question:
Within Push()
method, will it be a problem if multiple producers on different threads call this line mVector[index] = pMsg;
at the same time?
Can this code be improved further? Any comments are welcomed!
RingBuffer.h
#ifndef __RING_BUFFER_H_
#define __RING_BUFFER_H_
#include <atomic>
class RingBuffer
{
private:
std::vector<Foo *> mVector;
std::atomic<long> mWriteIdx{0}; //mWriteIdx will not exceed 2,000,000,000
std::atomic<long> mMaxReadIdx{0}; //mMaxReadIdx will not exceed 2,000,000,000
std::vector<long> mReadIdxVec;
public:
RingBuffer(int pNumOfConsumers);
void Push(Foo *);
Foo * TryRead(const int&);
};
#endif
RingBuffer.cc
#include "RingBuffer.h"
#define MAX_SIZE 1000
RingBuffer::RingBuffer(int pNumOfConsumers)
{
mVector.reserve(MAX_SIZE);
mVector.assign(MAX_SIZE, nullptr);
mReadIdxVec.assign(pNumOfConsumers, 0);
}
void RingBuffer::Push(Foo * pMsg)
{
if(!pMsg) return;
long writeIdx = mWriteIdx++;
long index = writeIdx % MAX_SIZE;
if(writeIdx >= MAX_SIZE) delete mVector[index];
mVector[index] = pMsg;
mMaxReadIdx++;
}
Foo * RingBuffer::TryRead(const int& pConsumer)
{
if(mReadIdxVec[pConsumer] >= mMaxReadIdx) return nullptr;
long index = mReadIdxVec[pConsumer] % MAX_SIZE;
mReadIdxVec[pConsumer]++;
return mVector[index];
}
Foo
in your code. Who's that and where did he come from? For future reference, please take a look at the How to get the best value out of Code Review - Asking Questions. \$\endgroup\$