The writer calling OneToOneUniQueue::push() must tell readers if it places the
first item into a previously empty queue. We used to determine emptiness prior
to incrementing queue size. That created a window between wasEmpty calculation
and queuing the new item (by incrementing the queue size). During that window,
the readers could pop() all previously queued items (resulting in an empty
queue) but since that happened after wasEmpty was computed to be false, the
writer would not notify them about the new item it just placed, and they will
get stuck, eventually resulting in queue overflow errors.
The fix attempts to increment the queue size and extract the previous size
value atomically.
if (full())
throw Full();
- const bool wasEmpty = empty();
const unsigned int pos = theIn++ % theCapacity * theMaxItemSize;
memcpy(theBuffer + pos, &value, sizeof(value));
- ++theSize;
+ const bool wasEmpty = !theSize++;
return wasEmpty && (!reader || reader->raiseSignal());
}