AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Multithreading GUI

Ein Thema von value is NULL · begonnen am 28. Jan 2014 · letzter Beitrag vom 29. Jan 2014
Antwort Antwort
Seite 1 von 2  1 2      
value is NULL

Registriert seit: 10. Sep 2010
249 Beiträge
 
#1

Multithreading GUI

  Alt 28. Jan 2014, 14:01
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:
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.
Prinzipiell mal die Frage: Wäre das so in ungefähr korrekt?
und 2. gibt es die Möglichkeit eine Art "Write" funktion zu schreiben wie zB:

Delphi-Quellcode:
function write(msg : string) : String;
begin
  Form1.Memo1.Lines.Add(msg);
end;
und diese aus dem Thread "Synchron" aufzurufen?

Vielen Dank im Voraus und sorry falls ich mich gerade blöd anstelle aber will hier nichts falsch machen ^^

LG
  Mit Zitat antworten Zitat
taveuni

Registriert seit: 3. Apr 2007
Ort: Zürich
533 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Multithreading GUI

  Alt 28. Jan 2014, 14:30
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.
Die obige Aussage repräsentiert meine persönliche Meinung.
Diese erhebt keinen Anspruch auf Objektivität oder Richtigkeit.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#3

AW: Multithreading GUI

  Alt 28. Jan 2014, 14:34
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:
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;
So ginge es auch.
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;
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#4

AW: Multithreading GUI

  Alt 28. Jan 2014, 14:35
Was hast Du für eine Delphi Version?
Schlecht wäre es nicht.

Zitat:
{$R *.fmx}
Aber sooooo alt ist Seine vermutlich nicht.

und Diesbezüglich hat sich, in letzter Zeit, eigentlich nicht viel geändert.

[edit]
http://www.delphipraxis.net/178791-t...iremonkey.html -> siehe Ausgangsfrage, letzte Zeile
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.159 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Multithreading GUI

  Alt 28. Jan 2014, 14:42
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 TMyOwnThread . Also

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 FreeOnTerminate := True setzen, das kann manchmal sehr praktisch sein - Der gibt sich dann von alleine wieder frei.

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: TThread.CreateAnonymousThread(..) 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.
  Mit Zitat antworten Zitat
value is NULL

Registriert seit: 10. Sep 2010
249 Beiträge
 
#6

AW: Multithreading GUI

  Alt 28. Jan 2014, 14:50
Danke für die Antworten!
Die verwendete Delphi Version ist Delphi XE5 Architect.

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;
Das hier klingt interessant. Ist es von Nachteil in so einer Procedure mehr zu verknüfpen? Plan wäre zB folgender:

Delphi-Quellcode:
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;
wobei es sich bei procedure1 zB um folgendes handelt:

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
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Multithreading GUI

  Alt 28. Jan 2014, 15:12
Ein schönes Tutorial zu Threads gibt es von Luckie:
http://www.michael-puff.de/Programmi...phi/Tutorials/

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.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#8

AW: Multithreading GUI

  Alt 28. Jan 2014, 15:12
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?
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
value is NULL

Registriert seit: 10. Sep 2010
249 Beiträge
 
#9

AW: Multithreading GUI

  Alt 28. Jan 2014, 15:17
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
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#10

AW: Multithreading GUI

  Alt 28. Jan 2014, 15:44
Zitat:
Delphi-Quellcode:
procedure procedure1();
begin
  Form1.Memo1.Lines.Add('procedure 1 gestartet');
  //irgendwelche dinge
  Form1.Memo1.Lines.Add('procedure 1 beendet');
end;
Was macht denn "irgendwelche dinge"?

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.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:32 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz