Unit ListFreeThread;

{
  Implementuje vlakno, ktere se stara o uvolnovani pameti po
  seznamech udalosti. Tyto seznamy mohou byt velmi dlouhe a mohou
  obsahovat velke mnozstvi prvku. Z tohoto duvodu jejich uvolnovani
  v primarnim vlakne muze brzdit praci GUI.
}

Interface

Uses
  Windows, Classes;


Type
  TListFreeThread = Class (TThread)
    Private
      FList : TList;
      FSemaphoreHandle : THandle;
      FCS : RTL_CRITICAL_SECTION;
      Function RemoveFirst:TList;
    Protected
      Procedure Execute; Override;
    Public
      Constructor Create(ASuspend:Boolean); Reintroduce; Virtual;
      Destructor Destroy; Override;
      Function AddList(AL:TList):Boolean;
      Procedure FinishWork;
    end;

Implementation

Uses
  SysUtils, Utils;

Procedure TListFreeThread.FinishWork;
begin
ReleaseSemaphore(FSemaphoreHandle, 1, Nil);
Terminate;
end;

Function TListFreeThread.AddList(AL:TList):Boolean;
{
  Prida zadany seznam udalosti do seznamu urceneho ke
  zniceni.

  Pokud uz vlakno dostalo signal ukoncit svoji cinnost, zadne
  dalsi polozky na uvolneni jiz neprijima.
}
begin
Result := Not Terminated;
If Result Then
  begin
  EnterCriticalSection(FCS);
  FList.Add(Pointer(AL));
  LeaveCriticalSection(FCS);
  ReleaseSemaphore(FSemaphoreHandle, 1, Nil);
  end;
end;

Function TListFreeThread.RemoveFirst:TList;
{
  Odebere prvni seznam ze seznamu seznamu udalosti
  na zniceni. Jedna se o neverejnou metodu.
}
begin
Result := Nil;
EnterCriticalSection(FCS);
If FList.Count > 0 Then
  begin
  Result := TList(FList[0]);
  FList.Delete(0);
  end;

LeaveCriticalSection(FCS);
end;

Procedure TListFreeThread.Execute;
{
  Hlavni smycka vlakna, ktera se vykonava,
  dokud neni ukonceno.

  Vlakno vzdy pocka, az se v seznamu seznamu udalosti
  na uvolneni objevi polozka (ci polozky, hlida se pres semafor).
  Nasledne tuto polozku odebere a postupne uvolni ji a vsechny
  jeji prvky z pameti. Pak zacne opet cekat.
}
Var
  L : TList;
  I : Integer;
begin
FreeOnTerminate := False;
Repeat
WaitForSingleObject(FSemaphoreHandle, INFINITE);
L := RemoveFirst;
If Assigned(L) Then
  begin
  For I := 0 To L.Count - 1 Do
    MemFree(L[I]);

  L.Free;
  end;

Until Not Assigned(L);
end;

Constructor TListFreeThread.Create(ASuspend: Boolean);
{
  Inicializuje novou instanci vlakna pro uvolnovani
  nepotrebnych seznamu udalosti.
}
begin
Inherited Create(True);
FList := TList.Create;
InitializeCriticalSection(FCS);
FSemaphoreHandle := CreateSemaphoreW(Nil, 0, 4096, Nil);
If FSemaphoreHandle = 0 Then
  Raise Exception.Create('Nepodarilo se vytvorit handle synchronizacni udalosti');

If Not ASuspend Then
  Resume;
end;

Destructor TListFreeThread.Destroy;
{
  Uvolni pamet a objekty, ktere vlakno potrebovalo behem
  sveho zivota.
}
begin
FList.Free;
CloseHandle(FSemaphoreHandle);
DeleteCriticalSection(FCS);
Inherited Destroy;
end;

End.

