Sign in Join
Wiki copytemporary

Multithreaded Application Tutorial/sk: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## Prehľad
22
33Tá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.
44
55Viacvláknový program je program, ktorý vytvorí dve a viacero vlákien pre vykonanie svojej práce v rovnaký čas.
66
77Jedno 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úť).
88
99Hlavná 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.
1010
1111Ď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é)
1212
1313Ďalšie možné využitie je pri sieťovom servery, kde sa musí obsluhovať naraz viac spojení.
1414
1515## Trieda TThread
1616
1717Najjednoduchší spôsob na vytvorenie viacvláknovej aplikácie je trieda TThread.
1818
1919Táto trieda umožnuje vytvorenie dodatočného vlákna (popri hlavnom) jednoduchým spôsobom.
2020
2121V štandardných prípadoch musíte overridnúť 2 metódy: konštruktor Create a procedúru Execute.
2222
2323V 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.
2424
2525Od 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.
2626
2727V overridnutej metóde Execute napíšete kôd ktorý sa má počas behu vlákna vykonať.
2828
2929Trieda TThread ma jednu veľmi dôležitú vlastnost: Terminated : boolean;
3030
3131Ak 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á)
3232
3333Zapamätajte si že vlasnosť Terminate nerobí sama o sebe nič. Je nutné naprogramovať metódu Execute tak, aby ju brala do úvahy.
3434
3535Ako 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.
3636
3737Ď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.
3838
3939Príklad:
4040
41-` Type`\
42-`   TMyThread = class(TThread)`\
43-`   private`\
44-`     fStatusText : string;`\
45-`     procedure ShowStatus;`\
46-`   public`\
47-`     Constructor Create(Suspended : boolean); override;`\
48-`     procedure Execute; override;`\
49-`   end;`
41+``` pascal
42+ Type
43+ TMyThread = class(TThread)
44+ private
45+ fStatusText : string;
46+ procedure ShowStatus;
47+ public
48+ Constructor Create(Suspended : boolean); override;
49+ procedure Execute; override;
50+ end;
51+```
5052
51-` constructor TMyThread.Create(Suspended : boolean);`\
52-` begin`\
53-`   inherited Create(Suspended);`\
54-`   FreeOnTerminate := True;`\
55-` end;`
53+``` pascal
54+ constructor TMyThread.Create(Suspended : boolean);
55+ begin
56+ inherited Create(Suspended);
57+ FreeOnTerminate := True;
58+ end;
59+```
5660
57-` procedure TMyThread.ShowStatus;`\
58-` begin`\
59-`   Form1.Caption := fStatusText;`\
60-` end;`\
61+``` pascal
62+ procedure TMyThread.ShowStatus;
63+ begin
64+ Form1.Caption := fStatusText;
65+ end;
6166
62-` procedure TMyThread.Execute;`\
63-` var`\
64-`   newStatus : string;`\
65-` begin`\
66-`   fStatusText := 'Starting...';`\
67-`   Synchronize(Showstatus);`\
68-`   fStatusText := 'Running...';`\
69-`   while (not Terminated) and ([vaša podmienka]) do`\
70-`     begin`\
71-`       ...`\
72-`       [sem vložte kód hlavného cyklu]`\
73-`       ...`\
74-`       if NewStatus <> fStatus then`\
75-`         begin`\
76-`           fStatusText = newStatus;`\
77-`           Synchronize(Showstatus);`\
78-`         end;`\
79-`     end;`\
80-` end;`
67+ procedure TMyThread.Execute;
68+ var
69+ newStatus : string;
70+ begin
71+ fStatusText := 'Starting...';
72+ Synchronize(Showstatus);
73+ fStatusText := 'Running...';
74+ while (not Terminated) and ([vaša podmienka]) do
75+ begin
76+ ...
77+ [sem vložte kód hlavného cyklu]
78+ ...
79+ if NewStatus <> fStatus then
80+ begin
81+ fStatusText = newStatus;
82+ Synchronize(Showstatus);
83+ end;
84+ end;
85+ end;
86+```
8187
8288On the application,
8389
84-` var`\
85-`   MyThread : TMyThread;`\
86-` begin`\
87-`   MyThread := TMyThread.Create(True); // Takto sa vlákno vytvorí "suspended"`\
88-`   ...`\
89-`   [sem vložte inicializačný kód]`\
90-`   ...`\
91-`   MyThread.Resume;`\
92-` end;`
90+``` pascal
91+ var
92+ MyThread : TMyThread;
93+ begin
94+ MyThread := TMyThread.Create(True); // Takto sa vlákno vytvorí "suspended"
95+ ...
96+ [sem vložte inicializačný kód]
97+ ...
98+ MyThread.Resume;
99+ end;
100+```
93101
94102## Dôležité veci na ktoré je treba dávať pozor
95103
96104Ak 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:
97105
98-`    MyThread:=TThread.Create(False);`\
99-`    if Assigned(MyThread.FatalException) then`\
100-`      raise MyThread.FatalException;`
106+``` pascal
107+ MyThread:=TThread.Create(False);
108+ if Assigned(MyThread.FatalException) then
109+ raise MyThread.FatalException;
110+```
101111
102112Tento 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á.
103113
104114## Unity podrebné na viacvláknové programovanie
105115
106116Vo windowse nieje treba žiadnych špeciálnych unít. V linuxe je treba použiť unitu cthreads, ktorá *musí* byť prvá v hlavnom programe!
107117
108118Váš program bude vizerať takto:
109119
110-` program MyMultiThreadedProgram;`\
111-` {$H+}`\
112-` uses`\
113-` {$ifdef linux}`\
114-`   cthreads,`\
115-` {$endif}`\
116-`   Interfaces, // this includes the LCL widgetset`\
117-`   Forms`\
118-`   { add your units here },`
120+``` pascal
121+ program MyMultiThreadedProgram;
122+ {$H+}
123+ uses
124+ {$ifdef linux}
125+ cthreads,
126+ {$endif}
127+ Interfaces, // this includes the LCL widgetset
128+ Forms
129+ { add your units here },
130+```
119131
120132## Podpora SMP
121133
122134------------------------------------------------------------------------
123135
124136Dobrá správa je, že pokiaľ vaša aplikácia beži na viacerých vláknach má automaticky podporu SMP!
125137
126138## Debugovanie viacvláknových programov v Lazaruse
127139
128140Debugovanie 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.
129141
130142Nieje známe riešenie ale jeden dočasný spôsob je:
131143
132144Vytvorenie novej inštancie X pomocou:
133145
134-` X :1 &`
146+```text
147+ X :1 &
148+```
135149
136150Naš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).
137151
138152Potom môžete ak chcete vytvoriť nové sedenie na X:
139153
140-` gnome-session --display=:1 &`
154+```text
155+ gnome-session --display=:1 &
156+```
141157
142158Potom v Lazaruse v nastavení projektu / run parameters zašktnite "Use display" a vložte :1.
143159
144160Teraz sa aplikácia spustí na X serveri č. 2 a vy ju môžete debugovať zo servera 1.
145161
146162Toto bolo otestované s Free Pascal 2.0 a Lazarus 0.9.10 na Windowse a Linuxe
147163
148164---
149165*From the Free Pascal wiki, page "Multithreaded Application Tutorial/sk", as it stood on 2006-05-28 after a change by Msmat, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history