Použití TThread.Synchronize u ne GUI aplikací

vložil Radek Červinka 4. července 2015 01:26

V rámci prověřování jednoho nápadu jsem chtěl vyzkoušel jak se chová TThread.Queue a TThread.Synchronize (více o těchto volání z dřívějška) u ne GUI aplikací (resp. zkoušel jsem jen konzolové).

Mějme v rámci běhu vlákna volání přes uvedené dvě metody (primárně se mají používat k synchronizaci UI z kontextu hlavního vlákna, ale řekněme, že s tím máme jiný záměr a nepoužijeme jiné synchronizační prostředky jako je např. kritická sekce, nebo TMonitor nebo …).

V rámci uvedených volání Delphi RTL zařadí vaše volání do fronty a podle varianty buďto pokračuje, nebo čeká na provedení. V GUI aplikacích hlavní vlákno (myslím, že v OnIdle, volá Classes.CheckSynchronize, které provede Vaše volání). Jenže u konzolových aplikací nic takového nemáme, resp. můžeme mít. Naštěstí se někdo u Delphi zamyslel a nechal vrátka pootevřena. Volání Queue předtím volitelně zkusí zavolat nastavenou (pokud je) Classes.WakeMainThread (což je metoda typu TNotifyEvent). Tato metoda musí pak zavolat uvedené Classes.CheckSynchronize a tím je hotovo.

Pokud stále toto bereme jako intelektuální cvičení tak:

program httpconsole;

//{ $APPTYPE CONSOLE}

uses
  SysUtils, Windows, Messages, Classes, http;

var
  oThread: TTCPHttpDaemon;

const
  WM_NULL= WM_USER + 100;

procedure WakeConsole(Sender: TObject);
begin
  PostThreadMessage(System.MainThreadID, WM_NULL, 0, 0);
end;

var
  WakeMainThread : TMethod = (Code:@WakeConsole; Data:Nil);

procedure WatchThreadFunc;
var
  Msg: TMsg;
begin
  Classes.WakeMainThread := TNotifyEvent(WakeMainThread);
  repeat
    GetMessage(Msg, 0, 0, 0);
    DispatchMessage(Msg);
    if Msg.Message = WM_NULL then
    begin
      Classes.CheckSynchronize;
    end;
  until (Msg.Message = WM_QUIT);
end;

begin
  try
    oThread := TTCPHttpDaemon.create;
//    writeln('Start');
    WatchThreadFunc;


    oThread.Terminate;
    oThread.WaitFor;
    oThread.Free;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Na začátku vytvoříme vlákno TTCPHttpDaemon (z nejmenovaného dema nejmenované TCP/IP knihovny) a v rámci jeho běhu voláme Queue, resp. Synchronize.

Zajímavější je WatchThreadFunc, kdy v rámci hlavního vlákna aplikace spustíme smyčku zpráv s čekáním na naši definovanou zprávu WM_NULL (a při jejím odchycení voláme Classes.CheckSynchronize).

Zde bych rád speciálně upozornil na konstrukci

var
  WakeMainThread : TMethod = (Code:@WakeConsole; Data:Nil);
…
  Classes.WakeMainThread := TNotifyEvent(WakeMainThread);

Tímto vytvoříme proměnnou typu metoda (tj. "proceduru objektu"), kdy objekt je nil, ale je to kompatibilní s uvedeným přiřazením. Funkce WakeConsole má parametry jako TNotifyEvent (tj. standardní obsluha např. tlačítka), jen jsme z ní udělali metodu.

No a WakeConsole pak jen pošle hlavnímu vláknu zprávu, na kterou čekáme.

Velmi by mne zajímal váš názor v komentářích, případně vylepšení nebo jiné řešení.

Tagy: ,

Praxe

Komentování ukončeno

Naše nabídka

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).

love Delphi

O Delphi.cz

Delphi je moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64, Mac OSX, Linux a na iPhone a Android.

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.

Poslední komentáře

Comment RSS

Dle měsíců