Difference between revisions of "Multithreaded Application Tutorial/sk"

From Free Pascal wiki
Jump to navigationJump to search
 
Line 7: Line 7:
 
Hlavné vlákno '''musí''' byt jediné, ktoŕe obnovuje komponenty, ktoré sú spojené s uživateľom (v opačnom prípade môže program uschnúť).
 
Hlavné vlákno '''musí''' byt jediné, ktoŕe obnovuje komponenty, ktoré sú spojené s uživateľom (v opačnom prípade môže program uschnúť).
  
The main idea is that the application can do some processing in background (in a second thread) while the user can keep working (using the main thread).
+
Hlavná myšlienka viacvláknového programovania spočíva v tom, že zatiaľ čo sa bude vykonávať vedľajšia činnosť ktorá by blokovoala, tak hlavné prostredie pre prácu s uživateľom môže fungovať ďalej ako hlavné vlákno.
  
Another use of threads is just to have a better responding application. If you create an application, and when the user press a button, the application start processing (a big job)... and while processing, the screen stop responding, and gives the user the sensation that the application is dead, that is not so nice. If the big job runs in a second thread, the application keeps responding (almost) as if it were idle. In this case it is a good idea, before starting the thread, to disable the buttons of the form to avoid the user to start more than one thread for the job.
+
Ďalšie použitie vlákien je ak chceme mať viacej raktívnu aplikáciu. Ak napr. vytvoríte aplikáciu v ktorej keď sa stlačí gombík tak sa spracuje veľa dát (spracovanie trvá..) tak by sa v normálnom prípade mohlo zdať že sa program "zasekol", čo nieje zrovna chcená vlastnosť. Ak by spracovanie bežalo vo vedlajšom vlákne, aplikácia zostáva reaktívnou ako keby sa nič nedialo. V takýchto prípadoch je dobrý zvyk povoliť štart len jedného vedlajšieho vlákna. (V opačnom prípade by mohli nastať nežiadúce situácie keď by užívateľ naštartoval viacej vlákien, ktoŕe by robili to isté)
  
Another use, is to create a server application that is able to respond to many clients at the same time.
+
Ďalšie možné využitie je pri sieťovom servery, kde sa musí obsluhovať naraz viac spojení.
  
== The TThread Class ==
+
== Trieda TThread ==
To create a multithreaded application, the easiest way is to use the TThread Class.
+
Najjednoduchší spôsob na vytvorenie viacvláknovej aplikácie je trieda TThread.
  
This class permits the creation of an additional thread (alongside the main thread) in a simple way.
+
Táto trieda umožnuje vytvorenie dodatočného vlákna (popri hlavnom) jednoduchým spôsobom.
  
Normally you only have to override 2 methods: the Create constructor, and the Execute method.
+
V štandardných prípadoch musíte overridnúť  2 metódy: konštruktor Create a procedúru Execute.
  
In the constructor, you will prepare the thread to run.
+
V konštruktore pripravíte vlákno na chod.
You will set the initial values of the variables or properties you need. The original constructor of TThread requires a parameter called Suspended.  
+
Nastavíte základné hodnoty premenným alebo vlastnostiam podľa potreby.
As guessed, being Suspended = True will prevent the thread to start automatically after the creation.  
+
Nadriadený konštruktor TThreadu vyžaduje parameter nazívaný Suspended.  
If Suspended = False, the thread will start running just after the creation.  
+
Ako ste možno uhádli, byť Suspended = True zabráni vláknu aby sa spustilo automaticky po vytvorení.  
If the thread is created suspended, then it will run only after the Resume method is called.
+
Ak Suspended = False, vlákno sa spustí hned po vytvorení.
 +
Ak ste vlákno vytvorili suspended, musíte ho "spustit" pomocou Resume.
  
As of FPC version 2.0.1 and later, TThread.Create also has an implicit parameter for Stack Size.
+
Od verzie FPC 2.0.1 a vyžšej má TThread.Create aj implicitný parameter Stack Size.
You can now change the default stack size of each thread you create if you need it.
+
Od teraz môžete meniť veľkosť stacku pre jednotlivé vlákna.
Deep procedure call recursions in a thread are a good example. If you don't specify the stack size parameter, a default OS stack size is used.
+
Dobrým príkladom využitia tohto parametra je, ak vo vlákne robíte hlboké rekurzie.
 +
Ak nešpecifikujete parameter Stack Size, tak je vybraná štandardná veľkosť v závislosti od operačného systému.
  
In the overrided Execute method you will write the code that will run on the thread.
+
V overridnutej metóde Execute napíšete kôd ktorý sa má počas behu vlákna vykonať.
  
The TThread class has one important property:  
+
Trieda TThread ma jednu veľmi dôležitú vlastnost:  
 
Terminated : boolean;
 
Terminated : boolean;
  
If the thread has a loop (and this is usual), the loop should be exited when Terminated is true (it is false by default). So in each cycle, it must check if Terminated is True, and if it is, must exit the .Execute method as quickly as possible, after any necessary cleanup.
+
Ak má vlákno cyklus (čo je obvyklé), musí sa v cykle kontrolovať, či je Terminated true (štandardne je false).
 +
Takže je nutné sa v každom prechode v cykle pozrieť, či je Terminated True, a ak áno, musí sa metóda Execute
 +
ukončiť tak rýchlo ako je to možne. (netreba zabúdať na uvolnenie pamäťe ak bola nejaka naalokovaná)
  
So keep in mind that the Terminate method does not do anything by default: the .Execute method must explicitly implement support for it to quit it's job.
+
Zapamätajte si že vlasnosť Terminate nerobí sama o sebe nič. Je nutné naprogramovať metódu Execute tak, aby ju brala do úvahy.
  
As we explained earlier, the thread should not interact with the visible components. To show something to the user it must do so in the main thread.  
+
Ako bolo vysvetlené, nieje možné aby sa z vedlajšieho vlákna nejakým spôsobom ovlivnovalo grafické prostredie a komponenty. Aby sme niečo uživateľovi ukázali, musíme to spraviť cez hlavné vlákno.
To do this, a TThread method called Synchronize exists.
+
Z tohto dôvodu existuje metóda Synchronize.
Synchronize requires a method (that takes no parameters) as an argument.  
+
Synchronize vyžaduje metódu (bez argumentov) ako argument.
When you call that method through Synchronize(MyMethod), the thread execution will be paused, the code of MyMethod will run in the main thread, and then the thread execution will be resumed.
+
Keď svoju metódu zavoláte cez Synchronize(MojaMetoda), vlákno bude "zapauznuté" a kód v MojaMetoda sa vykoná v hlavnom vlákne, po čom sa následne uvoľní vedlajšie vlákno.
  
There is another important property of TThread: FreeOnTerminate. If this property is true, the thread object is automatically freed when the thread execution (.Execute method) stops. Otherwise the application will need to free it manually.
+
Ďalšou dôležitou vlastnosťou je FreeOnTerminate. Ak je táto vlastnosť true, tak je objekt TThreadu automaticky uvoľnený z pamäti po dokončení vykonávania (metódy .Execute). V opačnom prípade musí aplikácia uvoľniť objekt sama.
  
Example:
+
Príklad:
  
 
   Type
 
   Type
Line 76: Line 80:
 
     Syncronize(Showstatus);
 
     Syncronize(Showstatus);
 
     fStatusText := 'Running...';
 
     fStatusText := 'Running...';
     while (not Terminated) and ([any condition required]) do
+
     while (not Terminated) and ([vaša podmienka]) do
 
       begin
 
       begin
 
         ...
 
         ...
         [here goes the code of the main thread loop]
+
         [sem vložte kód hlavného cyklu]
 
         ...
 
         ...
 
         if NewStatus <> fStatus then
 
         if NewStatus <> fStatus then
Line 94: Line 98:
 
     MyThread : TMyThread;
 
     MyThread : TMyThread;
 
   begin
 
   begin
     MyThread := TMyThread.Create(True); // This way it starts  automatically
+
     MyThread := TMyThread.Create(True); // Takto sa vlákno vytvorí "suspended"
 
     ...
 
     ...
     [Here the code initialices anythig required before the threads starts  executing]
+
     [sem vložte inicializačný kód]
 
     ...
 
     ...
 
     MyThread.Resume;
 
     MyThread.Resume;
 
   end;
 
   end;
  
== Special things to take care of ==
+
== Dôležité veci na ktoré je treba dávať pozor ==
There is a potential headache in Windows with Threads if you use the -Ct (stack check) switch.
+
Ak vo Windowse používate vlákna a máte zapnutú kontrolu pretečenia stacku (-Ct), vlákno sa nevykoná.
For reasons not so clear the stack check will "trigger" on any TThread.Create if you use the default stack size.
+
Z dôvodu implementácie kontroly stacku sa po TThread.Create vlákno nevykoná ale vyvolá vínimku.
The only work-around for the moment is to simply not use -Ct switch. Note that it does NOT cause an exception in
+
Táto vínimka NIEJE vyvolaná v hlavnom vlákne, čo znamená že nieje zaznamenaná.
the main thread, but in the newly created one. This "looks" like if the thread was never started.
+
Správny spôsob vytvárania vlákien aby ste výnimky zaznamenali je:
 
 
A good code to check for this and other exceptions which can occur in thread creation is:
 
  
  
Line 115: Line 117:
  
  
This code will asure that any exception which occured during thread creation will be raised in your main thread.
+
Tento kód zaruči, že ak sa pri vytváraní vlákna vyvolá vínimka, bude vyvolaná aj v hlavnom vlákne.
 +
Jeviný spôsob ako sa vo Windowse vyhnút tejto chybe je nepoužívať kontrolu stacku (prepínač -Ct).
 +
Kontrola stacku je štandardne vypnutá.
  
== Units needed for multithreaded application ==
+
== Unity podrebné na viacvláknové programovanie ==
On Windows, you don´t need any special unit for this to work.
+
Vo windowse nieje treba žiadnych špeciálnych unít.
On Linux, you need the cthreads unit and it ''must'' be the first used unit on the project (the program unit)!
+
V linuxe je treba použiť unitu cthreads, ktorá ''musí'' byť prvá v hlavnom programe!
  
So, your Lazarus application code should look like:
+
Váš program bude vizerať takto:
  
 
   program MyMultiThreadedProgram;
 
   program MyMultiThreadedProgram;
Line 133: Line 137:
 
     { add your units here },
 
     { add your units here },
  
== SMP Support ==
+
== Podpora SMP ==
 
----
 
----
The good news is that if your application works properly multithreaded this way, it is already SMP enabled!
+
Dobrá správa je, že pokiaľ vaša aplikácia beži na viacerých vláknach má automaticky podporu SMP!
  
== Debuging Multithreaded Applications with Lazarus ==
+
== Debugovanie viacvláknových programov v Lazaruse ==
The debugging on Lazarus is not fully functional yet. But, if you try to debug a multithreaded application on Linux, you will have one big problem: the X server will hang.
+
Debugovanie v lazaruse ešte nieje úplne funkčné.
 +
Ale ak sa pokúsite debugovat viacvláknovú aplikáciu v Linuxe uschne vám X server.
  
It is unknown how to solve this properly, but a workaround is:
+
Nieje známe riešenie ale jeden dočasný spôsob je:
  
Create a new instance of X with:
+
Vytvorenie novej inštancie X pomocou:
  
 
   X :1 &
 
   X :1 &
  
It will open, and when you switch to another desktop (the one you are working with pressing CTRL+ALT+F7), you will be able to go back to the new graphical desktop with CTRL+ALT+F8 (if this combination does not work, try with CTRL+ALT+F2... this one worked on Slackware).
+
Naštartuje sa nový X a keď prepnete do ďalšej plochy (stlačením CTRL+ALT+F7) budete môcť ísť späť do novej grafickej plochy stlačením CTRL+ALT+F8 (ak skratky nefungujú skúste CTRL+ALT+F2... to fungovalo na Slackware).
  
Then you could, if you want, create a desktop session on the X started with:
+
Potom môžete ak chcete vytvoriť nové sedenie na X:
  
 
   gnome-session --display=:1 &
 
   gnome-session --display=:1 &
  
Then, in Lazarus, on the run parameters dialog for the project, check "Use display" and enter :1.
+
Potom v Lazaruse v nastavení projektu / run parameters zašktnite "Use display" a vložte :1.
  
Now the application will run on the seccond X server and you will be able to debug it on the first one.
+
Teraz sa aplikácia spustí na X serveri č. 2 a vy ju môžete debugovať zo servera 1.
  
This was tested with Free Pascal 2.0 and Lazarus 0.9.10 on Windows and Linux.
+
Toto bolo otestované s Free Pascal 2.0 a Lazarus 0.9.10 na Windowse a Linuxe

Revision as of 18:57, 7 November 2005

Prehľad

Táto stránka vám pomôže s pochopením vývoja a debugovania viacvláknových programov s použitím Free Pascale a Lazarusa.

Viacvláknový program je program, ktorý vytvorí dve a viacero vlákien pre vykonanie svojej práce v rovnaký čas.

Jedno z vlákien je hlavné. Hlavné vlákno je vlákno vytvorené operačným systémom pri štarte programu. Hlavné vlákno musí byt jediné, ktoŕe obnovuje komponenty, ktoré sú spojené s uživateľom (v opačnom prípade môže program uschnúť).

Hlavná myšlienka viacvláknového programovania spočíva v tom, že zatiaľ čo sa bude vykonávať vedľajšia činnosť ktorá by blokovoala, tak hlavné prostredie pre prácu s uživateľom môže fungovať ďalej ako hlavné vlákno.

Ďalšie použitie vlákien je ak chceme mať viacej raktívnu aplikáciu. Ak napr. vytvoríte aplikáciu v ktorej keď sa stlačí gombík tak sa spracuje veľa dát (spracovanie trvá..) tak by sa v normálnom prípade mohlo zdať že sa program "zasekol", čo nieje zrovna chcená vlastnosť. Ak by spracovanie bežalo vo vedlajšom vlákne, aplikácia zostáva reaktívnou ako keby sa nič nedialo. V takýchto prípadoch je dobrý zvyk povoliť štart len jedného vedlajšieho vlákna. (V opačnom prípade by mohli nastať nežiadúce situácie keď by užívateľ naštartoval viacej vlákien, ktoŕe by robili to isté)

Ďalšie možné využitie je pri sieťovom servery, kde sa musí obsluhovať naraz viac spojení.

Trieda TThread

Najjednoduchší spôsob na vytvorenie viacvláknovej aplikácie je trieda TThread.

Táto trieda umožnuje vytvorenie dodatočného vlákna (popri hlavnom) jednoduchým spôsobom.

V štandardných prípadoch musíte overridnúť 2 metódy: konštruktor Create a procedúru Execute.

V konštruktore pripravíte vlákno na chod. Nastavíte základné hodnoty premenným alebo vlastnostiam podľa potreby. Nadriadený konštruktor TThreadu vyžaduje parameter nazívaný Suspended. Ako ste možno uhádli, byť Suspended = True zabráni vláknu aby sa spustilo automaticky po vytvorení. Ak Suspended = False, vlákno sa spustí hned po vytvorení. Ak ste vlákno vytvorili suspended, musíte ho "spustit" pomocou Resume.

Od verzie FPC 2.0.1 a vyžšej má TThread.Create aj implicitný parameter Stack Size. Od teraz môžete meniť veľkosť stacku pre jednotlivé vlákna. Dobrým príkladom využitia tohto parametra je, ak vo vlákne robíte hlboké rekurzie. Ak nešpecifikujete parameter Stack Size, tak je vybraná štandardná veľkosť v závislosti od operačného systému.

V overridnutej metóde Execute napíšete kôd ktorý sa má počas behu vlákna vykonať.

Trieda TThread ma jednu veľmi dôležitú vlastnost: Terminated : boolean;

Ak má vlákno cyklus (čo je obvyklé), musí sa v cykle kontrolovať, či je Terminated true (štandardne je false). Takže je nutné sa v každom prechode v cykle pozrieť, či je Terminated True, a ak áno, musí sa metóda Execute ukončiť tak rýchlo ako je to možne. (netreba zabúdať na uvolnenie pamäťe ak bola nejaka naalokovaná)

Zapamätajte si že vlasnosť Terminate nerobí sama o sebe nič. Je nutné naprogramovať metódu Execute tak, aby ju brala do úvahy.

Ako bolo vysvetlené, nieje možné aby sa z vedlajšieho vlákna nejakým spôsobom ovlivnovalo grafické prostredie a komponenty. Aby sme niečo uživateľovi ukázali, musíme to spraviť cez hlavné vlákno. Z tohto dôvodu existuje metóda Synchronize. Synchronize vyžaduje metódu (bez argumentov) ako argument. Keď svoju metódu zavoláte cez Synchronize(MojaMetoda), vlákno bude "zapauznuté" a kód v MojaMetoda sa vykoná v hlavnom vlákne, po čom sa následne uvoľní vedlajšie vlákno.

Ďalšou dôležitou vlastnosťou je FreeOnTerminate. Ak je táto vlastnosť true, tak je objekt TThreadu automaticky uvoľnený z pamäti po dokončení vykonávania (metódy .Execute). V opačnom prípade musí aplikácia uvoľniť objekt sama.

Príklad:

 Type
   TMyThread = class(TThread)
   private
     fStatusText : string;
     procedure ShowStatus;
   public
     Constructor Create(Suspended : boolean); override;
     procedure Execute; override;
   end;
 constructor TMyThread.Create(Suspended : boolean);
 begin
   inherited Create(Suspended);
   FreeOnTerminate := True;
 end;
 procedure TMyThread.ShowStatus;
 begin
   Form1.Caption := fStatusText;
 end;

 procedure TMyThread.Execute;
 var
   newStatus : string;
 begin
   fStatusText := 'Starting...';
   Syncronize(Showstatus);
   fStatusText := 'Running...';
   while (not Terminated) and ([vaša podmienka]) do
     begin
       ...
       [sem vložte kód hlavného cyklu]
       ...
       if NewStatus <> fStatus then
         begin
           fStatusText = newStatus;
           Syncronize(Showstatus);
         end;
     end;
 end;

On the application,

 var
   MyThread : TMyThread;
 begin
   MyThread := TMyThread.Create(True); // Takto sa vlákno vytvorí "suspended"
   ...
   [sem vložte inicializačný kód]
   ...
   MyThread.Resume;
 end;

Dôležité veci na ktoré je treba dávať pozor

Ak vo Windowse používate vlákna a máte zapnutú kontrolu pretečenia stacku (-Ct), vlákno sa nevykoná. Z dôvodu implementácie kontroly stacku sa po TThread.Create vlákno nevykoná ale vyvolá vínimku. Táto vínimka NIEJE vyvolaná v hlavnom vlákne, čo znamená že nieje zaznamenaná. Správny spôsob vytvárania vlákien aby ste výnimky zaznamenali je:


    MyThread:=TThread.Create(False);
    if Assigned(MyThread.FatalException) then
      raise MyThread.FatalException;


Tento kód zaruči, že ak sa pri vytváraní vlákna vyvolá vínimka, bude vyvolaná aj v hlavnom vlákne. Jeviný spôsob ako sa vo Windowse vyhnút tejto chybe je nepoužívať kontrolu stacku (prepínač -Ct). Kontrola stacku je štandardne vypnutá.

Unity podrebné na viacvláknové programovanie

Vo windowse nieje treba žiadnych špeciálnych unít. V linuxe je treba použiť unitu cthreads, ktorá musí byť prvá v hlavnom programe!

Váš program bude vizerať takto:

 program MyMultiThreadedProgram;
 {$H+}
 uses
 {$ifdef linux}
   cthreads,
 {$endif}
   Interfaces, // this includes the LCL widgetset
   Forms
   { add your units here },

Podpora SMP


Dobrá správa je, že pokiaľ vaša aplikácia beži na viacerých vláknach má automaticky podporu SMP!

Debugovanie viacvláknových programov v Lazaruse

Debugovanie v lazaruse ešte nieje úplne funkčné. Ale ak sa pokúsite debugovat viacvláknovú aplikáciu v Linuxe uschne vám X server.

Nieje známe riešenie ale jeden dočasný spôsob je:

Vytvorenie novej inštancie X pomocou:

 X :1 &

Naštartuje sa nový X a keď prepnete do ďalšej plochy (stlačením CTRL+ALT+F7) budete môcť ísť späť do novej grafickej plochy stlačením CTRL+ALT+F8 (ak skratky nefungujú skúste CTRL+ALT+F2... to fungovalo na Slackware).

Potom môžete ak chcete vytvoriť nové sedenie na X:

 gnome-session --display=:1 &

Potom v Lazaruse v nastavení projektu / run parameters zašktnite "Use display" a vložte :1.

Teraz sa aplikácia spustí na X serveri č. 2 a vy ju môžete debugovať zo servera 1.

Toto bolo otestované s Free Pascal 2.0 a Lazarus 0.9.10 na Windowse a Linuxe