Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Fragen zu Threads: Prozedur als Thread ausführen (https://www.delphipraxis.net/28560-fragen-zu-threads-prozedur-als-thread-ausfuehren.html)

Whistler 26. Aug 2004 13:28


Fragen zu Threads: Prozedur als Thread ausführen
 
Hallo,

ich würde gerne eine Prozedur als Thread ausführen, damit die Anwendung selbst weiterhin reagiert.
Habe mir bereits das Tutorial von Luckie angeschaut, jedoch hilft es mir auch nicht viel weiter.

Jelly 26. Aug 2004 14:05

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Hallo,

deine Frage ist etwas vage: "Ich habe ein Problem, kann mir jemand helfen" spiegelt ungefähr den Inhalt deines Problems... Also was genau willst du denn in dem Thread machen?

Gruß,

Whistler 26. Aug 2004 14:12

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Hallo,

dachte der Titel des Themas würde das klar machen:
Wenn der User auf einen Button klickt, wird eine Prozedur ausgeführt. Diese Prozedur benötigt viel Zeit. Während des Vorgangs, reagiert aber die Hauptanwendung nicht mehr. Daher will ich diese Prozedur in einem extra Thread ausführen.

Quasi:
User klickt Button -> Thread "DoProcess" erstellen -> Thread Auzführen (hier wird die eigentliche Prozedur ausgeführt) -> Wenn Thread Fertig -> Thread Ende.

weißer Zwerg 26. Aug 2004 14:19

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Hallo,

zum Thema Threads einfach mal bei Threads Tutorial vorbeischauen. Für den Anfang hat es mit sehr geholfen.

MfG wZ

nailor 26. Aug 2004 14:28

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
wo liegt den das problem? weil eigentlich zielt luckies tut genau darauf ab! wo kommst du nicht weiter?

Luckie 26. Aug 2004 14:28

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Wenn du eine konkrete Frage hast zu meinem Tutorial, was du nicht dabei verstanden hast, dann solltest du die auch stellen. Mit einem " jedoch hilft es mir auch nicht viel weiter" kann dir hier auch niemand weiterhelfen.

Pseudemys Nelsoni 26. Aug 2004 15:10

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
hi whissi,

versuchs mal so:

Delphi-Quellcode:
procedure blub;
var
  i: integer;
begin
  for i := 0 to 1000000 do
    Form1.ListBox1.Items.Add(IntToStr(i));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  id: cardinal;
begin
  createthread(nil, 0, @blub, nil, 0, id);
end;

Luckie 26. Aug 2004 15:19

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Und genau so bitte nicht!

Erstmal sollte man niemals direkt MSDN-Library durchsuchenCreateThread aufrufen.
Zitat:

Zitat von Delphi Hilfe
BeginThread encapsulates the Win32 CreateThread API call, but unlike CreateThread, it sets the global IsMultiThread variable, thereby making the heap thread-safe.

Dann entspricht die Thread-Routine nicht der Vorgabe, wie eine Thread-Funktion auszusehen hat. Sollte zwar auch gehen, würde ich aber nicht empfehlen. Die sieht nämlich so aus:
Zitat:

Zitat von Delphi Hiilfe
Delphi-Quellcode:
type TThreadFunc = function(Parameter: Pointer): Integer;

Dann wird ohne ein Schutzblock auf globale, sichtbare Ressourcen der VCL zugegriffen:
Delphi-Quellcode:
Form1.ListBox1.Items.Add(IntToStr(i));
Sollte zwar auch gut gehen, kann aber auch böse ins Auge gegehen. Stichwort an dieser Stelle MSDN-Library durchsuchenCrtitcalSection oder für die Delphi Hilfe: Delphi-Referenz durchsuchenTCriticalSection.

Whistler 17. Sep 2004 18:21

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Ich blicke es nicht :/

Das PDF als solches ist verständlich. Jedoch hilft es mir nicht weiter. Ich weiß eben nicht, wie ich nun hingehe und einen Thread aufrufe, der eine Funktion/Prozedur abarbeitet.

Ich will eigentlich nur folgendes:
Durch eine Aktion auf dem Hauptformular (z.B. Button-Click), soll eine Prozedur in einem eigenen Thread ausgeführt werden (nur als Info: die auszuführende Prozedur erstellt eine HASH-Summe) und wenn die Prozedur durchgelaufen ist (=Hashsumme erstellt wurde), soll sich der Thread wieder beenden und das Hauptform wieder aktiv werden.

Meflin 17. Sep 2004 18:26

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
wenn du die hauptform derweil deaktivierst, kannst du dir den thread auch sparen, denn dann ist er total überflüssig!

Whistler 17. Sep 2004 18:29

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Mir geht's um folgendes:
Wenn ich die HASH-Summe erstellen lasse, reagiert das Programm in der Zeit nicht. Daher will ich einen zusätzlichen "Prozess" (=Thread) starten, der dies macht.

Die Formulierung "deaktivieren" habe ich genutzt, weil ich nicht will, dass während der Thread, welche die HASH-Summe erstellt aktiv ist, der User das Programm munter weiter bedienen kann...

jfheins 17. Sep 2004 18:29

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
:arrow: Wenn du das Hauptform während der Threadausführung nicht brauchst, brauchst du auch keinen Thread (nur am Rande)

Aber zu deinem Problem:
Ich benutze immer Das Objekt Delphi-Referenz durchsuchenTThread
In die Klassenmethode TThread.Execute kommt das rein, was der Thread machen soll
Alle Zugriffe auf die VCL müssen in seperaten Klassenfunktoionen erfolgen, welche mit Delphi-Referenz durchsuchenSynchronize aufgerufen werden müssen

P.S. Wenn du regelmäßig Application.ProcessMessages aufrufst, reagiert dein Programm auch ...

Assarbad 17. Sep 2004 18:36

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Zitat:

Zitat von Luckie
Und genau so bitte nicht!

Erstmal sollte man niemals direkt MSDN-Library durchsuchenCreateThread aufrufen.

Also IMO gilt dies nur, wenn man auch den Memory-Manager von Delphi benutzt. Die Aussage ist also sehr fallabhängig!

Whistler 17. Sep 2004 18:46

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Eine Frage zu "Synchronize":
Ich verstehe nicht ganz wann ich es aufrufen muss. Delphi sagt:
Zitat:

{ Wichtig: Methoden und Eigenschaften von Objekten in visuellen Komponenten dürfen
nur in einer Methode namens Synchronize aufgerufen werden, z.B.

Synchronize(UpdateCaption);

und UpdateCaption könnte folgendermaßen aussehen:

procedure TMyThread.UpdateCaption;
begin
Form1.Caption := 'Aktualisiert in einem Thread';
end; }
Nur daraus würde ich schließen, dass wenn ich z.B. den Wert einer Variable im Mainform aktualisieren mmöchte, ich im Mainform eine Procedure schreiben müsste, welche ich im Thread per "Synchronize(Form1.Prozedurname);" aufrufen würde - das kann ich nicht ganz glauben.

Christian Seehase 17. Sep 2004 19:12

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Moin Whissi,

schau Dir das Beispiel doch noch mal genau an.
Die Methode die mit Synchronize aufgerufen wird ist eine Methode des Threads.

Whistler 17. Sep 2004 22:17

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Guten Abend,

Danke für die Antworten. Noch komme ich aber nicht weiter.
Ich habe nun folgendes gemacht:

Das Hauptformular erstellt ein "frmCheck". Das Fenster bekommt "ShowModal" Status und nach 1sek werden die Prozeduren abgearbeitet. Unter anderem rufe ich folgendes auf:
Code:
mCheck_Thread.TMyThread.Create(false);
("mCheck_Thread" ist die PAS-Datei, die den "Thread-Code" enthält (erstellt Mittels Delphi (Datei -> Neu...))

Die Prozedur wird auch abgearbeitet, jedoch beim Beenden steigt das Programm mit einer Zugriffsverletzung aus. Delphi makiert dann die Zeile "Timer1.Enabled := false;" der Prozedur "TfrmCheck.pd_CheckAll".
Den Thread synchronisiere ich Mittels "Synchronize(frmCheck.CheckAll);".

scp 18. Sep 2004 00:12

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Dazu ein paar Fragen:
- Was heisst nach 1sek? Per Timer?
- Wenn ja:
o Wann wird der ausgelöst? Im OnCreate oder OnShow?
o Wird der Thread innerhalb der Timerprozedur ausgelöst?
o Wenn ja: Timer1.Enabled := false; vor dem erstellen des Threads setzen.

Whistler 18. Sep 2004 00:20

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Ja, per Timer.
User klick auf frmMain einen Button und frmCheck wird erstellt. Im FormCreate Ereignis wird der Timer auf Enabled gesetzt. Im OnTimer Ereignis wird zu erst der Timer deaktiviert und dann eine andere Prozedur ausgeführt und schließlich die Prozedur aufgerufen, die den Thread starten soll.

Also wird der Timer VOR der Ausführung des Threads deaktiviert.

scp 18. Sep 2004 00:25

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Achso, ist Timer1 dann einer anderer Timer? Weil du ihn in pd_CheckAll ja nochmal deaktivierst, oder ist das die betreffende Timerprozedur?

Whistler 18. Sep 2004 00:28

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Form startet Timer.
Timer ruft CheckAll auf.
Check all ruft alle Sub-Routinen auf - u.a. die des Threads.

scp 18. Sep 2004 00:51

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Hmmm... dann fällt mir nur noch eins ein:
- Wie sieht es mit FreeOnTerminate aus? Ist das beim Thread auf true, damit der sich am Ende freigibt?
- Du erstellst den Thread direkt. Ich weis nicht, ob das Probleme macht, aber evtl. solltest du eine Variable im TfrmCheck definieren, der der Thread zugewiesen wird.
Delphi-Quellcode:
HashThread := mCheck_Thread.TMyThread.Create(false);

Sprint 18. Sep 2004 01:23

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Hallo Whissi,

also ohne deinen Quellcode zu sehen, kann man schlecht sagen wo der Fehler liegt. Ich weiß auch nicht welche Aufgabe der Timer in deinem Projekt hat.
Ich will dir aber anhand eines kleinen Beispiels zeigen, wie du einen Thread in deinem Projekt einsetzen kannst.
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    procedure OnThreadTerminate(Sender: TObject);
  public
    { Public-Deklarationen }
  end;

  TMyThread = class(TThread)
  public
    procedure Execute; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{--------------------------------------------------------------------------------------------------}

procedure TMyThread.Execute;
begin

  Sleep(2000);

end;

{--------------------------------------------------------------------------------------------------}

procedure TForm1.OnThreadTerminate(Sender: TObject);
begin

  Screen.Cursor := crDefault;
  Button1.Enabled := True;

end;

{--------------------------------------------------------------------------------------------------}

procedure TForm1.Button1Click(Sender: TObject);
begin

  Screen.Cursor := crHourGlass;
  Button1.Enabled := False;

  with TMyThread.Create(True) do
  begin
    FreeOnTerminate := True;
    OnTerminate := OnThreadTerminate;
    Resume;
  end;

end;

{--------------------------------------------------------------------------------------------------}

end.
Beim Klick auf den Button wird dieser deaktiviert und ein neuer Thread wird erstellt.
Beim erstellen wird der Constructor Create mit dem Wert True aufgerufen. So wird der Thread zwar erstellt aber noch nicht ausgeführt.
Jetzt können einige Werte gesetzt werden. Zum Beispiel FreeOnTerminate. Damit du dich nicht selber um die Klassenspeicherverwaltung kümmern musst.
Außerdem kannst du dort auch ein Ereignis setzten, das ausgeführt wird, wenn der Thread mit seiner Arbeit fertig ist.
Erst der Aufruf von Resume führt dann den Thread aus.
Ist der Thread beendet, wird das Ereignis OnThreadTerminate aufgerufen und der Button wird wieder aktiviert.

Whistler 18. Sep 2004 09:22

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Hallo,

vielen Dank!!!
Nach etwas herumspielen mit deinem Code-Beispiel konnte ich es 1:1 auf mein Projekt übertragen und habe es sogar verstanden (hoffe ich zumindest *G*). Jedenfalls macht das, was das Programm macht, Sinn ;-)

Danke noch einmal!

Whistler 18. Sep 2004 11:26

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
ARGHS!
Das war wohl doch zu Vorschnell. In meinem Test-Projekt hat's soweit geklappt.
Dort habe ich eben eine globale Variable im Wert verändert sowie Objekte des Formulars sichtbar/unsichtbar gemacht.

In dem richtigen Projekt, bekomme ich nun Zugriffsverletzungen. Dabei habe ich deinen Code 1:1 reinkopiert.

Whistler 18. Sep 2004 13:49

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Update:

Ich kann die Zugriffsverletzung nun klar festlegen:
Ich lass in dem Thread der Variable "HASH", welche sich auf dem Formular "frmCheck" befindet, die ermittelte MD5-Hash übergeben. Beim Schreiben in diese Variable, steigt er aus.

Dies ist mir jedoch unerklärlich, da ich mit der Variable zur Zeit weiter nichts mache - es sollte also kein Zugriff von anderen Forms auf die Variable existieren.

Imho muss ich hier nun synchronisieren, nur wie bzw. womit?

Sprint 18. Sep 2004 14:37

Re: Fragen zu Threads: Prozedur als Thread ausführen
 
Zitat:

Zitat von Whissi
Imho muss ich hier nun synchronisieren, nur wie bzw. womit?

Eigentlich nicht. Würde ich aber trotzdem machen.

Beispiel VCL Komponenten und Threads: (brauchst einen Button (Button1) und ein Textfeld (Edit1).
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

  TMyThread = class(TThread)
  private
    FEdit: TEdit;
    FHash: String;
    procedure Sync;
  protected
    procedure Execute; override;
  public
    constructor Create(Edit: TEdit; Hash: String);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{--------------------------------------------------------------------------------------------------}

constructor TMyThread.Create(Edit: TEdit; Hash: String);
begin

  inherited Create(True);
  FEdit := Edit;
  FHash := Hash;

end;

{--------------------------------------------------------------------------------------------------}

procedure TMyThread.Sync;
begin

  FEdit.Text := FHash;

end;

{--------------------------------------------------------------------------------------------------}

procedure TMyThread.Execute;
begin

  Synchronize(Sync);

end;

{--------------------------------------------------------------------------------------------------}

procedure TForm1.Button1Click(Sender: TObject);
begin

  with TMyThread.Create(Edit1, 'ABC123') do
  begin
    FreeOnTerminate := True;
    Resume;
  end;

end;

{--------------------------------------------------------------------------------------------------}

end.
Ein Beispiel wenn du mehrere Threads hast, die die selbe Variable zum Lesen und Schreiben benutzen:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

  TReadThread = class(TThread)
  protected
    procedure Execute; override;
  end;

  TWriteThread = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  Safe: TMultiReadExclusiveWriteSynchronizer;

procedure TReadThread.Execute;
begin

  with Safe do
  begin
    BeginRead;
      // hier kannst du sicher von deiner Variablen lesen
    EndRead;
  end;

end;

procedure TWriteThread.Execute;
begin

  with Safe do
  begin
    BeginWrite;
      // hier kannst du sicher in deine Variablen schreiben
    EndWrite;
  end;

end;

initialization
  Safe := TMultiReadExclusiveWriteSynchronizer.Create;

finalization
  if Assigned(Safe) then
    Safe.Free;

end.
Das Programm hat eigentlich keinen Auftrag, es soll dir nur zeigen wie du die Delphi Komponente TMultiReadExclusiveWriteSynchronizer einsetzen kannst.
Beim Lesen: BeginRead, EndRead
Beim Schreiben: BeginWrite, EndWrite

Der Fehler der bei dir Auftritt, hat aber wohl einen anderen Grund.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:55 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