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;
  LocalHandle: THandle;

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