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
534 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.313 Beiträge
 
Delphi 12 Athens
 
#3

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
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
value is NULL

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

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 Sir Rufo
Sir Rufo

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

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
 
#6

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.313 Beiträge
 
Delphi 12 Athens
 
#7

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.
Ein Therapeut entspricht 1024 Gigapeut.
  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, 16:00
Im Anhang das komplette Projekt und hier nur das Formular. Das ist nix mit massiv paralleler Verarbeitung der Jobs, sondern ein Thread kümmert sich um die Verarbeitung der übergebenen Jobs.

Inklusive der Rückmeldung an das Formular.
Delphi-Quellcode:
unit FormMain;

interface

uses
  ThreadedJobQueue, ProcJob,
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TMainForm = class( TForm )
    Button1 : TButton;
    CheckBox1 : TCheckBox;
    CheckBox2 : TCheckBox;
    CheckBox3 : TCheckBox;
    ListBox1 : TListBox;
    procedure Button1Click( Sender : TObject );
  private
    FJobQueue : TThreadedJobQueue;
    procedure LogStr( const AStr : string );
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
  end;

var
  MainForm : TMainForm;

implementation

{$R *.dfm}

procedure TMainForm.AfterConstruction;
begin
  inherited;
  FJobQueue := TThreadedJobQueue.Create;
end;

procedure TMainForm.BeforeDestruction;
begin
  inherited;
  FJobQueue.Free;
end;

procedure TMainForm.Button1Click( Sender : TObject );
begin
  if FJobQueue.IsWorking then
  begin
    LogStr( 'Nicht hektisch werden :o)' );
    Exit;
  end;

  if CheckBox1.Checked then
    FJobQueue.AddJob( TProcJob.Construct(
          procedure
      begin
        LogStr( 'Start 1' );
        Sleep( 1000 );
        LogStr( 'Ende 1' );
      end ) );

  if CheckBox2.Checked then
    FJobQueue.AddJob( TProcJob.Construct(
      procedure
      begin
        LogStr( 'Start 2' );
        Sleep( 1000 );
        LogStr( 'Ende 2' );
      end ) );

  if CheckBox3.Checked then
    FJobQueue.AddJob( TProcJob.Construct(
      procedure
      begin
        LogStr( 'Start 3' );
        Sleep( 1000 );
        LogStr( 'Ende 3' );
      end ) );

  FJobQueue.ProcessJobs;
end;

procedure TMainForm.LogStr( const AStr : string );
begin

  // Diese Methode achtet von selber darauf,
  // dass der eigentlich Zugriff im MainThread-Context erfolgt

  if MainThreadID = GetCurrentThreadId then
  begin

    ListBox1.ItemIndex := ListBox1.Items.Add( AStr );

  end
  else
    TThread.Queue( nil,
      procedure
      begin
        LogStr( AStr );
      end );
end;

end.
Angehängte Dateien
Dateityp: zip dp_178798.zip (2,9 KB, 45x aufgerufen)
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
Benutzerbild von stahli
stahli

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

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 himitsu
himitsu

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

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;
Ein Therapeut entspricht 1024 Gigapeut.
  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:31 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 by Thomas Breitkreuz