I need a thread-safe pool of Buffer-objects used in a round-robin fashion. I normally would just put a mutex in there to make the increment and modulo thread safe, but is it possible to write it using std::atomic? Here's a sample interface. If it makes things easier the total number of buffers can be a power of two. The next buffer index is never accessed outside of the class.
class Buffer;
class BufferManager
{
public:
BufferManager( size_t totalBuffers = 8 ) : mNextBufferIndex( 0 ), mTotalBuffers( totalBuffers )
{
mBuffers = new Buffer*[mTotalBuffers];
}
Buffer* GetNextBuffer()
{
// How to make this operation atomic?
size_t index = mNextBufferIndex;
mNextBufferIndex = ( mNextBufferIndex + 1 ) % mTotalBuffers;
return mBuffers[index];
}
private:
Buffer** mBuffers;
size_t mNextBufferIndex;
size_t mTotalBuffers;
};
Modulo can be safely used after choosing
std::atomic<size_t> mNextBufferIndex;
Buffer* GetNextBuffer()
{
// How to make this operation atomic?
size_t index = mNextBufferIndex ++;
size_t id = index % mTotalBuffers;
// If size could wrap, then re-write the modulo value.
// oldValue keeps getting re-read.
// modulo occurs when nothing else updates it.
size_t oldValue =mNextBufferIndex;
size_t newValue = oldValue % mTotalBuffers;
while (!m_mNextBufferIndex.compare_exchange_weak( oldValue, newValue, std::memory_order_relaxed ) )
newValue = oldValue % mTotalBuffers;
return mBuffers[id ];
}