Function SynchronizedCircularBuffer.dequeueSeveral

Note that if you use a semaphore to signal waiting threads, you should probably not call this.

T[] dequeueSeveral(
  return T[] buffer,
  scope void delegate() runInsideLockIfEmpty = null
);

If you use a set/reset event, there's a potential race condition between the dequeue and event reset. This is why the runInsideLockIfEmpty delegate is there - when it is empty, before it unlocks, it will give you a chance to reset the event. Otherwise, it can remain set to indicate that there's still pending data in the queue.