Synchronizace za pomocí System.TMonitor

vložil Radek Červinka 2. června 2010 23:06

V Delphi 2009 byla přidána pěkná možnost synchronizace přístupu k objektům. Do RTL, konkrétně system.pas, byl pro synchronizaci přidán záznam TMonitor (podobně je to řešeno v .NET).

Už několikrát jsem upozorňoval na opravdu nádherné možnosti získané díky rozšíření funkcionality record (alias záznamu). V starých Delphi byl záznam prostě jen blok strukturovaných dat, kdežto nyní nad ním můžete definovat metody, typy, class metody, případně class proměnné, viz. wiki Embarcadera. Níže schválně uvádím deklaraci TMonitor, samozřejmě nás zajímá jen sekce public, zbytek je jen jako příklad.

    1PPMonitor = ^PMonitor;
    2  PMonitor = ^TMonitor;
    3
    4  TMonitor = record
    5  strict private
    6    type
    7      PWaitingThread = ^TWaitingThread;
    8      TWaitingThread = record
    9        Next: PWaitingThread;
   10        Thread: Cardinal;
   11        WaitEvent: Pointer;
   12      end;
   13    var
   14      FLockCount: Integer;
   15      FRecursionCount: Integer;
   16      FOwningThread: Cardinal;
   17      FLockEvent: Pointer;
   18      FSpinCount: Integer;
   19      FWaitQueue: PWaitingThread;
   20    procedure QueueWaiter(var WaitingThread: TWaitingThread);
   21..
   22  public
   23    class procedure SetSpinCount(AObject: TObject; ASpinCount: Integer); static;
   24    class procedure Enter(AObject: TObject); overload; static; inline;
   25    class function Enter(AObject: TObject; Timeout: Cardinal): Boolean; overload; static;
   26    class procedure Exit(AObject: TObject); overload; static;
   27    class function TryEnter(AObject: TObject): Boolean; overload; static;
   28    class function Wait(AObject: TObject; Timeout: Cardinal): Boolean; overload; static;
   29    class procedure Pulse(AObject: TObject); overload; static;
   30    class procedure PulseAll(AObject: TObject); overload; static;
   31  end;

Pojmenování TMonitor není moc štastné, jelikož v jednotce Forms.pas již jeden TMonitor existuje, takže pozor na záměnu.

Kromě samostatného záznamu je v RTL několik procedur, které lze jednoduše použít.

    1function MonitorEnter(AObject: TObject; Timeout: Cardinal = INFINITE): Boolean; inline;
    2function MonitorTryEnter(AObject: TObject): Boolean; inline;
    3procedure MonitorExit(AObject: TObject); inline;
    4function MonitorWait(AObject: TObject; Timeout: Cardinal): Boolean; inline;
    5procedure MonitorPulse(AObject: TObject); inline;
    6procedure MonitorPulseAll(AObject: TObject); inline;
    7
    8procedure MemoryBarrier;
    9procedure YieldProcessor;

Jen pro úplnost: veškeré synchronizace jsou nahraditelné za vlastní obsluhu. Metody z TMonitor interně volají procedury definované přes System.MonitorSupport, takže pokud se vám nelíbí standardní obsluha (definovaná v SysUtils), nic Vám nebrání do System.MonitorSupport přiřadit vlastní implementace.

Použití TMonitor je přímočaré: kdekoliv potřebujeme přistupovat ke sdíleným datům z více vláken napíšeme např. pro přístup ke sdílenému TList

    1System.TMonitor.Enter(list);
    2  try
    3    list.Add(….);
    4    5  finally
    6    System.TMonitor.Exit(list); //vždy přes finally aby nedošlo při chybě k zablokování v tomto případě list
    7  end;

ekvivalentem je volání přes uvedené procedury

    1MonitorEnter(list);
    2  try
    3    list.Add(….);
    4    5  finally
    6    MonitorExit(list); //vždy přes finally, aby nedošlo při chybě k zablokování v tomto případě na objektu list
    7  end;

Kromě Enter a Exit, lze ještě využít Enter s dobou čekání (tj. vlákno bude čekat jen určitý čas na přístup k objektu jinak se volání ukončí a vrátí se False. Jinak ještě je možnost TryEnter, kdy se jen pokusíme o přístup bez čekání, Wait kdy se daný objekt zamkne po určitou dobu nebo Pulse a PulseAll co podle nápovědy jejich volání upozorní čekající vlákno(a), že první (jeden z čekajících) může zamknout objekt hned po opuštění drženým vláknem. Přiznám se, že mne moc nenapadá na co by to mohlo být dobré (třeba to někdo v komentářích ujasní). Ale tipuji, že většinou bude stačit kombinace Enter - Exit jak bylo naznačeno v příkladu.


Nabízíme Delphi školení a konzultace na různá témata, primárně ve Vaší firmě.

Tagy: , , ,

Delphi

Komentování ukončeno

Naše nabídka

Partial English version.

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy nebo burzy práce).

Pokud chcete podpořit tento server libovolnou částkou, můžete použít PayPal. Moc děkuji.

Delphi Certified Developer

O Delphi.cz

Delphi je jediný moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64 , Mac OSX a na iPhone a Android (s výhledem na další platformy díky FireMonkey) na současném trhu (včetně Windows 8.1).

V současnosti je světová komunita přes dva miliónů vývojářů.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Anketa

Poslední komentáře

Comment RSS