So I'm looking at Dmitriy's bounded MPMC queue. It is indeed as simple as it gets when it comes to a lock-free algorithm, the acid test being that it's simple enough that even I can understand it.
I noticed that if the CAS on enqueue_pos fails, the loop repeats, and re-checks the same cell it was just denied due to contention. If the other thread did not update sequence it can try to CAS the
enqueue_pos again which will always fail. If the other did update sequence then it drops into the else clause which updates pos from enqueue_pos.
It will work, but why have that extra loop iteration under contention? Couldn't you just write it as:
for (;;)
{
size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
cell = &buffer_[pos & buffer_mask_];
size_t seq = cell->sequence_.load(std::memory_order_acquire);
intptr_t dif = (intptr_t)seq - (intptr_t)pos;
if (dif == 0)
{
if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
break;
}
else if (dif < 0)
return false;
}
Which should always update pos after every CAS failure?
I may be missing something critical to my understanding of the algorithm.
Cheers,
Dan