TMultiWriteSingleReadLockFreeQueue: a late SetEvent from an earlier round...
Brought to you by:
twm
In u_dzMultiWriteSingleReadLockFreeQueue, Enqueue ends with
if InterlockedDecrement(FActiveWriters) = 0 then
FActiveWritersZeroEvent.SetEvent;
and Dequeue, after swapping the queues, does
FActiveWritersZeroEvent.ResetEvent;
if FActiveWriters <> 0 then
FActiveWritersZeroEvent.WaitFor(INFINITE);
and then reads the old write queue without checking FActiveWriters again.
Sequence:
FActiveWriters to 0 and is pre-empted before its SetEvent.FActiveWriters to 1, takes the current write queue and reserves a slot with InterlockedIncrement(FWriteIdx), but has not stored its item yet.ResetEvent, sees FActiveWriters = 1 and waits.SetEvent. That belongs to an earlier round, but it wakes the reader.FWriteIdx, which already includes B's slot, while B has not written it.Since the internal queues are reused (Reset does not clear FItems), the reader then gets whatever pointer that slot held in an earlier round, i.e. an item it already handed out and the caller may have freed. B's own item is lost, or ends up in a queue that has been reset.
Expected: after WaitFor returns, the reader re-checks FActiveWriters and waits again (with ResetEvent before the check) until it really is 0.
Found by reading the code during a code review, not reproduced: the window is a few instructions wide.
Fixed in revision [r2497].
Related
Commit: [r2497]