Race condition in JUCE Looping audio tutorial?

In this JUCE tutorial, which shows how to thread-safely play and loop audio, I see this code:

void checkForBuffersToFree()
{
    for (auto i = buffers.size(); --i >= 0;)                           // [1]
    {
        ReferenceCountedBuffer::Ptr buffer (buffers.getUnchecked (i)); // [2]
 
        if (buffer->getReferenceCount() == 2)                          // [3]
            buffers.remove (i);
    }
}

Isn’t that a race condition at [3]? What happens if in between the two statements

if (buffer->getReferenceCount() == 2)                          // [3]

and

   buffers.remove (i);

another thread acquires a pointer to that buffer? The reference count will then be 3 at the time the buffer gets removed here, and the other thread ends up with a dangling pointer.

Or did I overlook something?

If the above approach is indeed broken, how should we do this instead?

If I understood the example correctly, then there is no other place in the code, that fetches references from the buffers pool. The checkForPathToOpen method adds a reference into buffers and keeps its own currentBuffer reference to the same buffer. From that point, when the count has reached 1 (or 2 when the iterator of the release mechanism is reading), no other mechanism is accessing buffers.
Hence the reference count cannot increase after that point.

The buffers is so to say designed as a sink, it doesn’t supply references.

The term buffer is a bit overused in that example though :wink: