Lazarus: vlákno jako funkce

Libor.Karkoš

Lazarus: vlákno jako funkce
« kdy: 10. 06. 2018, 20:37:13 »
Dobrý den.Můj první pokus v lazaru.
Jsem si myslel, že když opráším staré učebnice ze školy, tak to dam, ale omyl  :(

Toto funguje v delphi
Kód: [Vybrat]
Function OtevriThread(Param: Pointer): Longint;
begin
  beep;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 thh: THandle;
 thid: Cardinal;
begin
 thh:=BeginThread(nil,0,@OtevriThread,nil,0,thid);
 if (thh<>0) then CloseHandle(thh);
end;

V lazarusu není funkce CloseHandle, tak jsem nahradil za CloseThread(thh) a pod win take ok.
Když to však chci pod linuxem, tak mi to CloseHandle shodí celou apku.

Neporadí někdo?
« Poslední změna: 11. 06. 2018, 09:24:48 od Petr Krčmář »


sj

Re:Lazarus - Vlakno jako funkce
« Odpověď #1 kdy: 10. 06. 2018, 21:39:14 »
Očividně to je špatný způsob. Tak jsem zkusil kouknout na help.

V helpu k BeginThread https://www.freepascal.org/docs-html/rtl/system/beginthread.html je uvedena funkce EndThread (tak jako to bývá u typicky párových funkcí ve všech dokumentacích všech jazyků, u otevírací je zmíněno jak se naopak zavírá) která zavře současné vlákno https://www.freepascal.org/docs-html/rtl/system/endthread.html.

Proč by někdo chtěl zavírat současné vlákno a ne nějaké jiné? Protože zavraždit nějaké jiné vlákno je špatné, samo vlákno se má rozhodnout že chce skončit protože ví v jakém je stavu a že je to bezpečné. Co kdyby třeba to vlákno mělo otevřený handle souboru? Naalokovanou paměť? Typicky v jiných programovacích jazycích se to řeší tak že "worker" má cyklus ve kterém vykonává práci (a třeba čas od času zavolá nějakou funkci kterou dá najevo že toho udělalo dost a že mohou třeba začít pracovat jiná vlákna (docela užitečné na jednovláknovém systému)), a jen si čas od času kontroluje jestli nemá skončit.

Ve to zdá se funguje podobně - něco je popsáno v http://wiki.freepascal.org/Multithreaded_Application_Tutorial a používá se funkce Terminate. Ale trochu jednodušeji mi přijde že je to vysvětleno v https://stackoverflow.com/questions/3788743/correct-thread-destroy či https://stackoverflow.com/questions/3557105/free-a-tthread-either-automatically-or-manually?noredirect=1&lq=1 případně https://stackoverflow.com/questions/4044855/how-to-kill-a-thread-in-delphi.

Osobně mi ale přijde že nějak Free Pascalu chybí nějaký jednoduchý a rychlý tutorial na tohle :-(.

m

Re:Lazarus - Vlakno jako funkce
« Odpověď #2 kdy: 10. 06. 2018, 21:55:20 »
Nezávisle na platformě by měla fungovat třída TThread:
https://www.freepascal.org/docs-html/rtl/classes/tthread.html

Zdědit a napsat vlastní funkci Execute.

Jednoduchý příklad viz. dokumentace:
/examples/multithreading/

Libor.Karkoš

Re:Lazarus - Vlakno jako funkce
« Odpověď #3 kdy: 11. 06. 2018, 08:36:47 »
Tak mi to nedalo a hledal jsem jak to pořešít.
http://forum.lazarus.freepascal.org/index.php?topic=11011.0
Tu klučina píše, že místo CloseHandle použil EndThread.

Kód: [Vybrat]
var
  Form1: TForm1;
  thh: THandle;

implementation

{$R *.lfm}

{ TForm1 }
Function OtevriThread(Param: Pointer): Longint;
begin
  beep;
  EndThread (thh);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  thid: Cardinal;
begin
  thh:=BeginThread(nil,0,@OtevriThread,nil,0,thid);
end;                       


Při kliknutí na gombik se vytvoří vlákno, které provede to co chcí a pak se samo ukončí.
Je to funkční a vypadá že i v pořádku  ;)

Libor.Karkoš

Re:Lazarus - Vlakno jako funkce
« Odpověď #4 kdy: 11. 06. 2018, 08:43:17 »
Ale ne pod linuxem  :'(
Zasek mi to shodí celou apku


sj

Re:Lazarus - Vlakno jako funkce
« Odpověď #5 kdy: 11. 06. 2018, 09:01:19 »
Dalo by se poslat kompletní kód který aktuálně používáš a ktery tedy nefunguje? Jestli tam máš více logiky (kterou třeba nechceš zveřejnit) tak to zjednoduš až na minimální příklad který stále crashuje.

Psal na to třeba můžeme zkusit mrknout, nebo zkusit zreplikovat.

cinnamon

Re:Lazarus - Vlakno jako funkce
« Odpověď #6 kdy: 11. 06. 2018, 09:19:37 »
Ale ne pod linuxem  :'(
Zasek mi to shodí celou apku

V Linuxu musí být pro vícevláknovou aplikaci v projektu unity navíc:

http://wiki.freepascal.org/Multithreaded_Application_Tutorial#Units_needed_for_a_multi-threaded_application

jestli třeba není problém v tom.

Libor.Karkoš

Re:Lazarus - Vlakno jako funkce
« Odpověď #7 kdy: 11. 06. 2018, 10:43:10 »
Dalo by se poslat kompletní kód který aktuálně používáš
Není žádný kompletní kod.
Teprve chci můj projekt předelat do vlakna, tak zkouím zda to pujde.
Prostě jeden button a jedna funkce.

PetrM

Re:Lazarus - Vlakno jako funkce
« Odpověď #8 kdy: 11. 06. 2018, 13:00:41 »
Dalo by se poslat kompletní kód který aktuálně používáš
Není žádný kompletní kod.
Teprve chci můj projekt předelat do vlakna, tak zkouím zda to pujde.
Prostě jeden button a jedna funkce.

>>> Multiplatformní zapouzdření třídou TThread

Libor.Karkoš

Re:Lazarus: vlákno jako funkce
« Odpověď #9 kdy: 13. 06. 2018, 09:18:11 »
Tak problémy s chybovými hlášky při spouštění a i to padaní apky řeší toto.
http://forum.lazarus.freepascal.org/index.php?topic=18470.0
Problém je, že se mi žadné vlákno nespustí.
http://delphiexamples.com/application/appsynchthread.html

Libor.Karkoš

Re:Lazarus: vlákno jako funkce
« Odpověď #10 kdy: 16. 06. 2018, 08:51:55 »
Klucí, ještě by byl jeden dotaz.
Jak správně zapisovat z vlakna třeba do labelu

Kód: [Vybrat]
procedure TTestThread.Execute;
var
  s: string;
begin
  s:=StavExpanderu('i2cget -y 1 0x22 0x13');
  Form1.Label1.Caption:= s;
  Form1.Memo1.Clear;
  Form1.Memo1.Lines.Add(s) ;
end;             

Memo je ok.
Label vyhazuje http://img24.cz/images/86959613333661778055.png

Když to upravím takto tak stejný problém
Form1.Label1.Caption:= '';
Form1.Label1.Caption:= s;   

Když to však mam takto, tak to funguje.Proč?
Form1.Label1.Caption:= 'xxx';
Form1.Label1.Caption:= s; 
Co dělam špatně?

cinnamon

Re:Lazarus: vlákno jako funkce
« Odpověď #11 kdy: 16. 06. 2018, 09:46:53 »
Klucí, ještě by byl jeden dotaz.
Jak správně zapisovat z vlakna třeba do labelu

Kód: [Vybrat]
procedure TTestThread.Execute;
var
  s: string;
begin
  s:=StavExpanderu('i2cget -y 1 0x22 0x13');
  Form1.Label1.Caption:= s;
  Form1.Memo1.Clear;
  Form1.Memo1.Lines.Add(s) ;
end;             

Memo je ok.
Label vyhazuje http://img24.cz/images/86959613333661778055.png

Když to upravím takto tak stejný problém
Form1.Label1.Caption:= '';
Form1.Label1.Caption:= s;   

Když to však mam takto, tak to funguje.Proč?
Form1.Label1.Caption:= 'xxx';
Form1.Label1.Caption:= s; 
Co dělam špatně?

Dělá se to pomocí Synchronize a popsáno je to na wiki:

http://wiki.freepascal.org/Multithreaded_Application_Tutorial#The_TThread_Class

odkazy posílal výše sj měl by sis to přečíst, ušetří ti to čas a docela objasní spoustu věcí souvisejících s vlákny...