![]() |
Multithreading GUI
Hallo liebe Community!
Kaum ist das eine Problem gelöst, schon taucht das nächste auf. Und zwar bin ich auf der Suche nach einem guten Multithreading Tutorial. Gefunden habe ich schon einiges, will jedoch TThread verwenden. Die Aufgabe: Ich habe eine Formularanwendung auf der sich ein Memo befindet sowie ein Start Button. Wenn ich auf Start klicke, werden verschiedenste Funktionen und Prozeduren aufgerufen. Diese Prozeduren will ich jetzt als Thread laufen lassen. Ich hätte mir das ungefähr so gedacht:
Delphi-Quellcode:
Prinzipiell mal die Frage: Wäre das so in ungefähr korrekt?
unit Unit1;
interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Ani, FMX.Layouts, FMX.Gestures, FMX.Memo, FMX.StdCtrls; type TForm1 = class(TForm) StyleBook1: TStyleBook; Memo1: TMemo; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; type TMyOwnThread = class(TThread) private { Private-Deklarationen } protected procedure Execute; override; public { Public-Deklarationen } end; procedure test; var Form1: TForm1; implementation {$R *.fmx} procedure test; var i : Integer; begin i := 0; while i <= 20 do begin Form1.Memo1.Lines.Add(IntTostr(i)); i := i + 1; end; end; procedure TMyOwnThread.Execute; begin try Synchronize(test); except on e: exception do begin Showmessage(e.Message); end; end; end; procedure TForm1.Button1Click(Sender: TObject); var thread : TMyOwnThread; begin thread := TMyOwnThread.Create(False); thread.WaitFor; thread.Free; end; end. und 2. gibt es die Möglichkeit eine Art "Write" funktion zu schreiben wie zB:
Delphi-Quellcode:
und diese aus dem Thread "Synchron" aufzurufen?
function write(msg : string) : String;
begin Form1.Memo1.Lines.Add(msg); end; Vielen Dank im Voraus und sorry falls ich mich gerade blöd anstelle aber will hier nichts falsch machen ^^ LG |
AW: Multithreading GUI
Was hast Du für eine Delphi Version?
Könntest Du die unter Umständen freundlicherweise eintragen? Abhängig davon fallen die Antworten unterschiedlich aus. |
AW: Multithreading GUI
Wenn du die meiste Zeit synchronisiert in der GUI rumhängst, dan bringt der Thread garnichts und ist eher kontraproduktiv.
Du kannst aber eine TStringList in den Thread nehmen, da alles einfügen und am Ende alles Gemeinsam via AddStrings ins Memo einfügen. (oder zumindestens grüppchenweise weniger oft übergeben) Du kannst in dem Thread alles machen, aber sobald "globale" nicht threadsichere dinge genutzt werden, mußt du synchronisieren oder sonstwie die Zugriffe regeln. Ach ja, wenn du zu oft Synchronize aufrufst, also vorallem viele Male extrem schnell hinterinander, dann kannst du damit den GUI-Thread lahmlegen, da er keiner Zeit mehr für seinen eigenen Kram hat. Im Delphi find ich einmalig genutzte und "kurze" Sync-Methoden via Generics, genauer als anonyme Methode oftmals irgendwie übersichtlicher. Vorallem da man dort Parameter Variablen übergeben bekommt, ohne daß Diese global sein müssen. (was Probleme gibt, wenn die Methode+Variable von mehreren Threads aus gleichzeigt aufgerufen werden kann)
Delphi-Quellcode:
So ginge es auch.
procedure TMyOwnThread.Execute;
begin try Synchronize(nil, procedure var i : Integer; begin i := 0; while i <= 20 do begin Form1.Memo1.Lines.Add(IntTostr(i)); i := i + 1; end; end); except on e: Exception do ShowMessage(e.Message); end; end;
Delphi-Quellcode:
procedure TMyOwnThread.Execute;
var i : Integer; begin try i := 0; Synchronize(nil, procedure begin while i <= 20 do begin Form1.Memo1.Lines.Add(IntTostr(i)); i := i + 1; end; end); except on e: Exception do ShowMessage(e.Message); end; end; |
AW: Multithreading GUI
Zitat:
Zitat:
und Diesbezüglich hat sich, in letzter Zeit, eigentlich nicht viel geändert. [edit] ![]() |
AW: Multithreading GUI
Jetzt haben mich doch einige überholt. Hier trotzdem der Text:
Warum baumelt die Methode "test" da so einsam herum? Das gehört doch zu deinem
Delphi-Quellcode:
. Also
TMyOwnThread
Delphi-Quellcode:
TMyOwnThread = class(TThread)
protected procedure test(); procedure Execute(); override; end; bzw. TMyOwnThread = class(TThread) private procedure test(); protected procedure Execute(); override; end; Wenn du einen Thread nicht irgendwo manuell freigeben willst, kannst du auf deiner Threadvariable auch
Delphi-Quellcode:
setzen, das kann manchmal sehr praktisch sein :-) - Der gibt sich dann von alleine wieder frei.
FreeOnTerminate := True
Warum wartest du im OnClick-Handler auf den Thread? Das führt doch das Konzept eines Thread ad absurdum. Es soll doch gerade nicht die Oberfläche blockiert werden, sondern etwas im Hintergrund geschehen. Oder war das gerade nur, weil du ihn ordentlich wieder freigeben wolltest, wenn er zu Ende ist? Letztendlich: Zum testen sicher gut, aber bitte gewöhn dir für die Praxis besser nicht an, von einem Thread aus etwas in die Formulare "hineinzu-synchronisieren". Der Thread ist für Hintergrund-Arbeiten da. Weiterhin: Ich finde den Exception-Handler im Thread eher unsinnig. Ich habe noch nicht ganz verstanden, welches Schreckensszenario himitsu eben an die Wand gemalt hat, aber wenn in einem Thread eine Exception ganz nach oben bubbelt dann wird er beendet. Aber doch bitte nicht die ganze Anwendung? PS: Ein VCL-ShowMessage erstellt ein Formular. In einem Thread keine gute Sache. Bei Firemonkey blicke ich spontan nicht durch. Kann man das in einem Thread überhaupt machen? PPS:
Delphi-Quellcode:
ist an sich eine tolle Sache. Sonderlich viel leserlicher finde ich das nicht, insbesondere wenn es umfangreich wird. Für kleine Dinge aber eine Tolle Sache.
TThread.CreateAnonymousThread(..)
|
AW: Multithreading GUI
Danke für die Antworten!
Die verwendete Delphi Version ist Delphi XE5 Architect.
Delphi-Quellcode:
Das hier klingt interessant. Ist es von Nachteil in so einer Procedure mehr zu verknüfpen? Plan wäre zB folgender:
procedure TMyOwnThread.Execute;
var i : Integer; begin try i := 0; Synchronize(nil, procedure begin while i <= 20 do begin Form1.Memo1.Lines.Add(IntTostr(i)); i := i + 1; end; end); except on e: Exception do ShowMessage(e.Message); end; end;
Delphi-Quellcode:
wobei es sich bei procedure1 zB um folgendes handelt:
procedure TMyOwnThread.Execute;
var i : Integer; begin try i := 0; Synchronize(nil, procedure begin if Form1.CheckBox1.IsChecked then procedure1; if Form1.CheckBox2.IsChecked then procedure2; if Form1.CheckBox3.IsChecked then procedure3; if Form1.CheckBox4.IsChecked then procedure4; if Form1.CheckBox5.IsChecked then procedure5; if Form1.CheckBox6.IsChecked then procedure6; end); except on e: Exception do ShowMessage(e.Message); end; end;
Delphi-Quellcode:
--------------------------------------------------------------
procedure procedure1();
begin Form1.Memo1.Lines.Add('procedure 1 gestartet'); //irgendwelche dinge Form1.Memo1.Lines.Add('procedure 1 beendet'); end; Was ich eigentlich zu erreichen versuche, vermutlich habe ich das nicht richtig rüber gebracht, Der User wählt diverse Dinge aus per checkbox und dementsprechend werden dann verschiedene Funktionen aufgerufen die ihre arbeit verrichten. Jede Funktion schreibt diverse Infos in ein Memo (ich taufe dies jetzt mal "LiveLog") Das heisst ich will natürlich: A) Das GUI nicht zum "freeze" bringen und B) von jeder procedure dann auf die Komponenten wie Checkboxen, TEdit's, Memo zugreifen |
AW: Multithreading GUI
Ein schönes Tutorial zu Threads gibt es von Luckie:
![]() Ich spiele auch gerade mit Threads und GUI (aber nicht VCL und FMX) herum. Man darf grundsätzlich nicht schreibend aus zwei Threads auf einen Speicherplatz zugreifen. Entweder kann man undefinierte Ergebnisse erhalten oder direkt Zugriffsfehler. Das kann man sich gut an einer Liste verdeutlichen. Wenn ein Thread gerade einen neuen Eintrag anhängen will und ein anderer zum gleichen Zeitpunkt den ersten Eintrag entfernt wird das zu einem Fehler führen. Das selbe Problem besteht bei Zugriffen auf die GUI-Controls. Um diese Probleme zu vermeiden gibt es CriticalSections. Thread1 "sperrt den Speicherplatz oder eine Komponente" bis er fertig ist mit seiner Aufgabe. Solange muss Thread2 warten und kann seine Aufgabe erst danach erledigen. Syncronisize kapselt intern eine CriticalSection und vereinfacht so deren Verwendung (geht aber nur bei der Syncronisierung mit dem Mainthread). Bei langen Berechnungen muss man überlegen, wie oft man Syncronisize aufruft, da das den Berechnungsthread bremst (er muss warten bis der Mainthread fertig ist). In Bezug auf die VCL oder FMX wäre ich nicht sicher, ob sich dabei alle Probleme vermeiden lassen. Warum verwendest Du überhaupt Threads? Soll der Anwender zwischendurch weiter arbeiten können? Nur dann machen Threads wirklich Sinn. Andernfalls könntest Du Deine Schalter deaktivieren und in Deinen Funktionen gelegentlich Application.Processmessages aufrufen. Dann würde man die Einträge im Memo sehen und das Formular optisch noch etwas tun. |
AW: Multithreading GUI
Nein, so macht man das nie, niemals, nicht.
Wenn der Thread startet, dann greift der nicht mehr auf die Form zu. Und schon gar nicht über die globale Form-Variable. Das knallt sonst schneller als du denkst. Und wenn du alles, was du ausführen möchtest synchronisiert ausführst, wofür dann erst einen Thread? |
AW: Multithreading GUI
Prinzipiell soll er mit der GUI eigentlich nichts mehr machen können.
Das einzige was halt "schön" wäre.. wenn sich das Memo wie ein "liveLog" verhält. Sprich: es wird eine Funktion aufgerufen die bestimmte dinge erledigt und schreibt das ins memo Dann wird funktion2 aufgerufen und schreibt seinen Status in das Memo usw usw ... Der User soll halt sehen, das sich da was tut. Jetzt ist es so, das nach dem Durchlauf das Memo vollgeschrieben wird, sprich wenn schon alle Funktionen fertig sind :/ Deswegen habe ich an Threads gedacht |
AW: Multithreading GUI
Zitat:
Wenn da nichts mit der GUI oder was anderem Globalen gemacht wird, dann solltest du nur die beiden Lines.Add synchronisieren und nicht die ganze Prozedur. So würde das "irgendwelche dinge" im Thread laufen und nicht die GUI blockieren. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:46 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz