|
@@ -34,6 +34,7 @@ public:
|
|
virtual bool enqueue(const ELEMENT item) = 0;
|
|
virtual bool enqueue(const ELEMENT item) = 0;
|
|
virtual bool dequeue(ELEMENT & result) = 0;
|
|
virtual bool dequeue(ELEMENT & result) = 0;
|
|
virtual bool tryDequeue(ELEMENT & result) = 0;
|
|
virtual bool tryDequeue(ELEMENT & result) = 0;
|
|
|
|
+ virtual void noteReaderStopped() = 0;
|
|
virtual void noteWriterStopped() = 0;
|
|
virtual void noteWriterStopped() = 0;
|
|
virtual void abort() = 0;
|
|
virtual void abort() = 0;
|
|
virtual void reset() = 0;
|
|
virtual void reset() = 0;
|
|
@@ -100,7 +101,7 @@ class ReaderWriterQueue
|
|
const static state_t fixedSlotMask = (1U << fixedSlotBits) - 1;
|
|
const static state_t fixedSlotMask = (1U << fixedSlotBits) - 1;
|
|
|
|
|
|
public:
|
|
public:
|
|
- ReaderWriterQueue(unsigned _maxWriters, unsigned _maxItems) : maxItems(_maxItems), maxWriters(_maxWriters)
|
|
|
|
|
|
+ ReaderWriterQueue(unsigned _maxWriters, unsigned _maxReaders, unsigned _maxItems) : maxItems(_maxItems), maxReaders(_maxReaders), maxWriters(_maxWriters)
|
|
{
|
|
{
|
|
//printf("element(%u) pad(%u) write(%u), read(%u) slot(%u) count(%u) max(%u)\n", stateBits, padBits, writerBits, readerBits, maxSlotBits, countBits, maxItems);
|
|
//printf("element(%u) pad(%u) write(%u), read(%u) slot(%u) count(%u) max(%u)\n", stateBits, padBits, writerBits, readerBits, maxSlotBits, countBits, maxItems);
|
|
//Check all the bits are used, and none of the bits overlap.
|
|
//Check all the bits are used, and none of the bits overlap.
|
|
@@ -130,6 +131,7 @@ public:
|
|
dynamicSlotMask = fixedSlotMask;
|
|
dynamicSlotMask = fixedSlotMask;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ activeReaders.store(maxReaders, std::memory_order_relaxed);
|
|
activeWriters.store(maxWriters, std::memory_order_relaxed);
|
|
activeWriters.store(maxWriters, std::memory_order_relaxed);
|
|
aborted.store(false, std::memory_order_relaxed);
|
|
aborted.store(false, std::memory_order_relaxed);
|
|
state.store(0, std::memory_order_relaxed);
|
|
state.store(0, std::memory_order_relaxed);
|
|
@@ -160,6 +162,9 @@ public:
|
|
unsigned curCount = (curState & countMask);
|
|
unsigned curCount = (curState & countMask);
|
|
if (curCount == maxItems)
|
|
if (curCount == maxItems)
|
|
{
|
|
{
|
|
|
|
+ if (allReadersStopped())
|
|
|
|
+ return false;
|
|
|
|
+
|
|
if (--numSpins != 0) // likely
|
|
if (--numSpins != 0) // likely
|
|
{
|
|
{
|
|
curState = state.load(std::memory_order_acquire);
|
|
curState = state.load(std::memory_order_acquire);
|
|
@@ -174,6 +179,8 @@ public:
|
|
{
|
|
{
|
|
if (aborted.load(std::memory_order_acquire))
|
|
if (aborted.load(std::memory_order_acquire))
|
|
return false;
|
|
return false;
|
|
|
|
+ if (allReadersStopped())
|
|
|
|
+ return false;
|
|
writers.wait();
|
|
writers.wait();
|
|
if (aborted.load(std::memory_order_acquire))
|
|
if (aborted.load(std::memory_order_acquire))
|
|
return false;
|
|
return false;
|
|
@@ -237,6 +244,8 @@ public:
|
|
if (aborted.load(std::memory_order_relaxed))
|
|
if (aborted.load(std::memory_order_relaxed))
|
|
return false;
|
|
return false;
|
|
|
|
|
|
|
|
+ dbgassertex(!allReadersStopped());
|
|
|
|
+
|
|
unsigned numSpins = initialSpinsBeforeWait;
|
|
unsigned numSpins = initialSpinsBeforeWait;
|
|
//Note, compare_exchange_weak updates curState when it fails, so don't read inside the main loop
|
|
//Note, compare_exchange_weak updates curState when it fails, so don't read inside the main loop
|
|
state_t curState = state.load(std::memory_order_acquire);
|
|
state_t curState = state.load(std::memory_order_acquire);
|
|
@@ -341,11 +350,22 @@ public:
|
|
|
|
|
|
virtual void reset()
|
|
virtual void reset()
|
|
{
|
|
{
|
|
|
|
+ activeReaders.store(maxReaders, std::memory_order_relaxed);
|
|
activeWriters.store(maxWriters, std::memory_order_relaxed);
|
|
activeWriters.store(maxWriters, std::memory_order_relaxed);
|
|
aborted.store(false, std::memory_order_relaxed);
|
|
aborted.store(false, std::memory_order_relaxed);
|
|
readers.reinit(0);
|
|
readers.reinit(0);
|
|
writers.reinit(0);
|
|
writers.reinit(0);
|
|
}
|
|
}
|
|
|
|
+ virtual void noteReaderStopped()
|
|
|
|
+ {
|
|
|
|
+ //MORE: If this reduces activeProducers to 0 then it may need to wake up any waiting threads.
|
|
|
|
+ if (--activeReaders <= 0)
|
|
|
|
+ {
|
|
|
|
+ state_t curState = state.load(std::memory_order_acquire);
|
|
|
|
+ unsigned writersWaiting = (unsigned)((curState & writerMask) >> writerShift);
|
|
|
|
+ writers.signal(writersWaiting);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
virtual void noteWriterStopped()
|
|
virtual void noteWriterStopped()
|
|
{
|
|
{
|
|
//MORE: If this reduces activeProducers to 0 then it may need to wake up any waiting threads.
|
|
//MORE: If this reduces activeProducers to 0 then it may need to wake up any waiting threads.
|
|
@@ -367,12 +387,15 @@ public:
|
|
writers.signal(writersWaiting);
|
|
writers.signal(writersWaiting);
|
|
}
|
|
}
|
|
inline bool allWritersStopped() const { return activeWriters.load(std::memory_order_acquire) <= 0; }
|
|
inline bool allWritersStopped() const { return activeWriters.load(std::memory_order_acquire) <= 0; }
|
|
|
|
+ inline bool allReadersStopped() const { return activeReaders.load(std::memory_order_acquire) <= 0; }
|
|
|
|
|
|
protected:
|
|
protected:
|
|
BufferElement * values;
|
|
BufferElement * values;
|
|
unsigned dynamicSlotMask;
|
|
unsigned dynamicSlotMask;
|
|
unsigned maxItems;
|
|
unsigned maxItems;
|
|
|
|
+ unsigned maxReaders;
|
|
unsigned maxWriters;
|
|
unsigned maxWriters;
|
|
|
|
+ std::atomic<int> activeReaders;
|
|
std::atomic<int> activeWriters;
|
|
std::atomic<int> activeWriters;
|
|
std::atomic<bool> aborted;
|
|
std::atomic<bool> aborted;
|
|
Semaphore readers __attribute__((aligned(CACHE_LINE_SIZE)));
|
|
Semaphore readers __attribute__((aligned(CACHE_LINE_SIZE)));
|