procedure TBoundedBuffer.ResetState;

{ Closes handles and deallocates memory.
  Note that this must unblock threads in such a manner that they quit cleanly }

var
  SemCount: integer;

begin
  if FBufInit then
  begin
    WaitForSingleObject(FCriticalMutex, DefaultWaitTime);
    FBufInit := false;
    FBufSize := 0;
    FreeMem(FBuf);
    repeat
      ReleaseSemaphore(FEntriesFree, 1, @SemCount);
    until SemCount = 0;
    repeat
      ReleaseSemaphore(FEntriesUsed, 1, @SemCount);
    until SemCount = 0;
    CloseHandle(FEntriesFree);
    CloseHandle(FEntriesUsed);
    CloseHandle(FCriticalMutex);
  end;
end;