![]() |
Prozedur mit Parametern an Thread übergeben
Hallo,
ich habe einen Thread, dem ich eine Prozedur übergeben möchte, die dann in diesem Thread ausgeführt wird. Das sieht bis jetzt so aus:
Code:
type
TReportThread = Class(TThread) public Proc : Procedure of object; protected procedure Execute; override; end; procedure TReportThread.Execute; begin try Proc; except // Error handling end; end; Den Thread starte ich folgendermaßen:
Code:
procedure TService1.AdsEvent1Notification(Sender: TObject; event: string;
count: Integer; eventdata: string); var reportThread : TReportThread; begin reportThread := TReportThread.Create(True); reportThread.Proc := dmReports.printPersonalList; reportThread.Resume; end; // Hier ist die Prozedur die vom Thread ausgeführt werden soll procedure TdmReports.printStart(); begin // Code end; Soweit klappt das auch alles. Nun würde ich gerne der Prozedur die dem Thread übergeben wird einen Parameter mitgeben. Ich habe schon einiges versucht, aber bin leider im gescheitert. Wäre nett wenn mir da einer weiter helfen könnte... Vielen Dank! |
AW: Prozedur mit Parametern an Thread übergeben
einfach der Procedure mitgeben geht nicht. denn letzendlich gibst du nur die Adresse der Procedure mit. Die Parameter musst du entsprechend ebenso an den Thread übergeben wie die Procedure selbst (also mehrere Properties (bzw. einen Record der alle Werte enthält))
|
AW: Prozedur mit Parametern an Thread übergeben
Delphi-Quellcode:
TReportThread = class(TThread)
public type TThreadedProc: procedure(const AInt: Integer; const AStr: String) of object; private FParam1 : Integer; FParam2 : String; FProc : TThreadedProc; protected procedure Execute(); override; public property Param1 : Integer read FParam1 write FParam1; property Param2 : String read FParam2 write FParam2; property Proc : TThreadedProc read FProc write FProc; end; procedure TReportThread.Execute(); begin try Proc(FParam1, FParam2); except end; end; |
AW: Prozedur mit Parametern an Thread übergeben
Welche Delphiversion nutzt du? (das kann man nicht umsonst im Profil angeben)
Mit anonymen Methoden kann man, in neueren Delphis, diesbezüglich nette Spielchen betreiben. |
AW: Prozedur mit Parametern an Thread übergeben
Hi,
danke für die Antworten! @ s.h.a.r.k Sehe ich das richtig das ich bei diesem Weg dann die Parameter der zu übergebenden Funktionen entfernen muß und stattdessen die privaten Variablen des Thread nutze? @ himitsu 2009...habe mal mein Profil editiert :wink: Dann werde ich mal etwas über anonyme Funktionen lesen.. |
AW: Prozedur mit Parametern an Thread übergeben
Nein, die Parameter bleiben definitiv vorhanden, schau dir doch mal den Typen an, den ich da deklariert habe. Allerdings musst du den Umweg über die Properties gehen, das ist das was SirThornberry schon gesagt hat.
|
AW: Prozedur mit Parametern an Thread übergeben
Hi shark,
irgendwas passt da bei mir nocht nicht. Der Code sieht jetzt folgendermaßen aus:
Code:
Aber beim zuweisen der Funktion erhalte ich einen Fehler:
...
type TThreadedProc = procedure(const AFileName : String) of object; type TReportThread = Class(TThread) private FParam1 : String; FProc : TThreadedProc; protected procedure Execute(); override; public property Param1 : String read FParam1 write FParam1; property Proc : TThreadedProc read FProc write FProc; end; ...
Code:
Fehler: Inkompatible Typen: 'string' und 'procedure, untyped pointer or untyped parameter'
...
reportThread := TReportThread.Create(True); reportThread.Proc := dmReports.printPersonalList(sRequestId); reportThread.Resume; ... Für einen Tipp wäre ich nochmals dankbar |
AW: Prozedur mit Parametern an Thread übergeben
Delphi-Quellcode:
Du musst die Property setzen, so wie ich gerade gezeigt habe. Du setzt mit
...
reportThread := TReportThread.Create(True); reportThread.Proc := dmReports.printPersonalList; reportThread.Param1 := 'Ein Wert ;)'; reportThread.Resume; ...
Delphi-Quellcode:
ja nur den Pointer auf die Methode. An der Stelle hat das nichts mit den Parametern zu tun. Schau dir vielleicht mal Events genauer an, das ist ja auch nichts anderes -- vor allem, wenn du dynamisch Events definierst.
reportThread.Proc := ...
PS: Du solltest noch eine Getter- und Setter-Methode einführen, die das Lesen und Schreiben via CriticalSections absichert. Sonst kannst du unter Umständen Probleme bekommen. PPS: Es gibt auch [delphi] Tags ;) |
AW: Prozedur mit Parametern an Thread übergeben
![]()
Delphi-Quellcode:
type
TSimpleThread = class(TThread) private FProc: TThreadProcedure; protected procedure Execute; override; public class procedure CreateThread(Proc: TThreadProcedure); end; procedure TSimpleThread.Execute; begin FProc; end; class procedure TSimpleThread.CreateThread(Proc: TThreadProcedure); var Thread: TSimpleThread; begin Thread := TSimpleThread.Create(True); Thread.FProc := Proc; Thread.FreeOnTerminate := True; Thread.Start; end; var TheParam, TheParam2: String; begin TheParam := 'der Text'; TheParam2 := 'Caption'; TSimpleThread.CreateThread(procedure begin // von hier ... MessageBox(0, PChar(TheParam), PChar(TheParam2), 0); // bis hier wird alles im Thread ausgeführt ^^ end); |
AW: Prozedur mit Parametern an Thread übergeben
Zitat:
|
AW: Prozedur mit Parametern an Thread übergeben
Dann mach einfach die Quotes weg ;)
|
AW: Prozedur mit Parametern an Thread übergeben
Ja, reine Zitatposts sind halt nicht erlaubt,
bzw. Zitate werden nicht mit gezählt. |
AW: Prozedur mit Parametern an Thread übergeben
"Softwaredesigntechnisch" ist man mit der Idee eine Prozedur einem Thread mitzugeben völlig auf dem Holzweg!
Warum? Ganz einfach, weil die Prozedur ja nicht im luftleeren Raum steht, sondern sie braucht auch Daten, mit denen sie arbeiten kann. Diese Daten können natürlich in globalen Variablen zu finden sein, aber ich glaube über die negativen Auswirkungen von globalen Variablen wurde schon genügend diskutiert. Eine Prozedur + dazu gehörende Daten ist aber nichts anderes als ein Objekt. Anonyme Methoden oder Closures sind im Prinzip auch Objekte - sie bestehen aus der Methode ohne Namen sowie den "eingefrorenen" Daten zum Zeitpunkt ihrer Zuweisung. Man kann es drehen und wenden wie man will; das was ein Thread tun soll (die "Arbeit" oder der Job) ist irgendwie immer eine Art von Objekt. Wenn man sauber programmieren möchte, dann lässt man am Besten Objekte auch wie Objekte aussehen und leitet ganz normal von TThread ab:
Delphi-Quellcode:
Im Prinzip ist es ganz einfach:
TMeinThread = class(TThread)
public procedure Execute;override; // Eingabewerte property Report: ..... ..... // Ausgabewerte property xyz: TXyz .... end; man muss überlegen, was der Thread zum Arbeiten als Input braucht. Der Zugriff auf globale Variablen oder Singletons ist tabu; wir übergeben die Daten über ein Property. (selbst dann wenn die Daten letztendlich in einer globalen Variablen stecken) Nachdem der Thread gelaufen ist muss man die Ergebnisse abgreifen. Häufig ist es so, dass die Eingabevariablen gleichzeitig auch Speicher für die Ergebnisse sind. Dann werden keine Properties für die Ausgabewerte benötigt und wir sind fertig. |
AW: Prozedur mit Parametern an Thread übergeben
Anonyme Methoden sind eigentlich Interfaces mit einer öffentlich Methode.
"Übegebene" Variablen werden als Kopie in diesem Interface angelegt. Bei übergebenen lokalen Variablen wird, sobald sie innerhalb des aktuellen Prozeduraufrufs verändert werden, jeweils die Kopie aktualisiert. Diese Aktualisierung gilt nur für den aktuellen Aufruf, wird die lokale Variable freigegeben, wird auch ihre Verbindung getennt und wird auch im nächten Prozeduraufruf nicht wiederverbunden. Globale Variablen sollte man nicht übergeben oder nur threadsicher aufrufen, wozu auch externe Felder in Objekten zählen. |
AW: Prozedur mit Parametern an Thread übergeben
*angestaubten Thread hochhol*
Hallo, da mein Anliegen dem Thread sehr ähnlich ist möchte ich keinen Neuen öffnen. Vorweg: Ich habe bis jetzt noch nicht mit Threads gearbeitet. Ich habe nun schon eine ganze Weile mehrere Foren und Tutorials durchgeguckt aber so richtig klar ist mir das ganze noch nicht. Ich bin mir auch nicht 100%ig sicher, ob ein Thread für mich die richtige Lösung ist, da mein Programmablauf trotzdem sequentiell bleiben soll. Ausgangssituration: Ich habe eine Procedure in Unit A, welche einen Funktion in Unit B aufruft. Dieser Funktion werden Werte übergeben aufgrund dessen ein Gerät angesteuert wird, welches Messwerte liefert. Diese Messwerte werden dann wieder in den Werten gespeichert. Der Ablauf der Funktion dauert je nach Einstellungen 5-30 Sekunden. In dieser Zeit ist das Hauptprogramm nicht bedienbar. Das ist das Problem. So soll es z.B. auch möglich sein die Messung vorzeitig zu beenden. Ich habe mal versucht den Aufbau auf das nötigste zu beschränken.
Delphi-Quellcode:
unit Main
interface uses Data; {...} procedure TMain.Messung; var FData: TData; i: integer; Messzeit: integer; Messwert: double; begin FData := TData.Create; for i := 0 to 5 do begin {Einlesen von Messparametern} Messzeit := 5; Messwert := 0; FData.Messen(Messzeit, Messwert); {Weiterarbeiten mit wirklicher Messzeit und Messwert} end; FreeAndNil(FData); end;
Delphi-Quellcode:
Es handelt sich also um eine Funktion mit var-Parametern. Die Schleife in der Main-Unit soll auch erst weiterlaufen, wenn die funktion "Messen" abgeschlossen ist.
unit Data
{...} type TData = class public function Messen(var Messzeit: integer; var Messwert: double): boolean; end; Das ganze muss ich für viele verschiedene Funktionen mit unterschiedlichen Parametern machen. Gibt es da eine Allround-Lösung? Wenn ich die Funktion als Procedure schreibe und das Beispiel von himitsu in Beitrag #9 verwende erhalte ich folgenden Fehler beim Aufruf von TMyThread.CreateThread(Procedure): Inkompatible Type: 'TThreadProcedure' und 'procedure, untyped pointer or untyped parameter' Ich habe auch versucht der Klasse TMyThread die Parameter über Properties vorher zu übergeben, dann den Thread zu starten und später wieder auszulesen. Leider wird der Execute-Abschnitt nicht sofort ausgeführt und meine Schleife läuft bereits weiter, bevor die Werte berechnet wurden. Die Beispiele im Internet sind leider auch alle sehr allgemein gehalten und viele Dokumente, auf die in Foren verwiesen wurde, existieren nicht mehr. Ich hoffe Ihr könnt mir einen Denkanstoß geben Grüße Headbucket |
AW: Prozedur mit Parametern an Thread übergeben
Wenn die VCL hängt und das nicht passieren soll, dann gibt es nur zwei Möglichkeiten:
- die Operation in einen Thread auslagern, damit der Hauptthread nicht blockiert wird - immer mal wieder der VCL Zeit geben etwas zu tun (Application.ProcessMessages) Wenn die Arbeit im aufrufenden Thread sequentiell bleiben soll, dann gibt es auch da mehrere Möglichkeiten: - die aufrufende Prozedur im Hauptthread wartet, bis der Thread fertig ist. (muß beim Warten aber der VCL Zeit zum Arbeiten geben) - der Thread sagt dem Hauptthread, daß sie fertig ist und in diesem Event wird dann die restliche/nachfolgene Arbeit verrichtet Zitat:
Bei einer anonymen Methode kann man z.B. lokale Variablen indirekt übergeben => nicht via Parameter, sondern eher so, wie man auch eine Variable innerhalb eines Blocks (z.B. in einem IF oder einer FOR-Schleife) verwendet. Oder man nutzt "globale" Variablen zum Zwischenspeichern, oder man erstellt eine eigene TThread-Klasse, wo die Werte via Felder der Klasse übergeben werden. In die Felder kommt es dann z.B. mittels Parameter im Constuctor oder als Property (bei verzögertem Start). |
AW: Prozedur mit Parametern an Thread übergeben
Vielen Dank schonmal für die Antwort. Ich habe mich eben nochmal rangesetzt und bin ein Stück weiter, denke ich.
Zitat:
Ich starte eine Messung und muss diese z.B: nach 5 Sekunden wieder beenden. Die 5 Sekunden überbrücke ich mit einem Sleep. Wenn ich das Sleep durch eine Schleife realisiere und immer "Application.ProcessMessages" ausgebe, werden aus den 5 Sekunden mal ganz schnell 12. Vllt werde ich das nochmal mit einem Timer versuchen. Das ganze in einem Thread auslagern gefällt mir aber ehrlich gesagt noch besser. Ich habe die Übergabe der Parameter jetzt erstmal mit einem globalen Record gelöst, da es ein kleine Programm mit wenig Daten ist. Kein Problem also. Ich habe nun ein ganz neues Problem. Ich starte z.B. zwei Threads:
Delphi-Quellcode:
Die erste Funktion (GetSPL) ruft eine Klassen-Funktion einer anderen Unit auf. Diese Funktion soll eine EXE-Datei starten und warten, bis diese beendet ist. Die Funktion sieht dabei so aus (habe ich auch aus dem Forum glaube ich):
hMyThread[0] := CreateThread(nil, 0, TFNThreadStartRoutine(@GetSPL), nil, 0, iThreadID);
hMyThread[1] := CreateThread(nil, 0, TFNThreadStartRoutine(@GetVoltage), nil, 0, iThreadID); WaitForMultipleObjects(2, @hMyThread, true, Infinite);
Delphi-Quellcode:
Leider bleibt er dann beim eigentlichen Aufruf der EXE-Datei stehen. Es muss ja irgendwie mit dem "WaitForMultipleObjects" zusammenhängen. Aber wieso? Muss ich diese Funktion nochmal in einen dritten Thread packen?
function TMeasurement.StartAndWait(const ExecuteFile,ParamString: string): boolean;
var SEInfo : TShellExecuteInfo; ExitCode : DWORD; begin Result := False; if not FileExists(ExecuteFile) then Exit; FillChar(SEInfo, SizeOf(SEInfo), 0); SEInfo.cbSize := SizeOf(TShellExecuteInfo); with SEInfo do begin fMask := SEE_MASK_NOCLOSEPROCESS; Wnd := Application.Handle; lpFile := PChar(ExecuteFile); lpParameters := PChar(ParamString); nShow := SW_SHOWMINIMIZED; end; if ShellExecuteEx(@SEInfo) then //hier bleibt er nun stehen und es geht nicht weiter begin repeat Application.ProcessMessages; Sleep(100); GetExitCodeProcess(SEInfo.hProcess, ExitCode); until (ExitCode <> STILL_ACTIVE) or Application.Terminated; Result := True; end; end; Grüße Headbucket Edit: Ich habe es jetzt mit einer abgeleiteten Klasse von TThread gelöst. Wenn ich den Funktionsaufruf dort in Execute habe, läuft alles Problemlos durch. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:19 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