![]() |
Anfängerfragen zu Threads (TThread)
Hallo *.*,
um die Reaktionsfähigkeit eines meiner Programme zu verbessern, denke ich gerade darüber nach, Threads zu verwenden, um bestimmte Funktionen von diesem ausführen zu lassen. Die Situation stellt sich folgendermaßen dar:
Delphi-Quellcode:
Die Ausführung von FObject.Ping kann aufgrund von mir nicht beeinflussbaren Faktoren sehr lange dauern (bei Nichterreichbarkeit der IP durchaus 20 Sekunden). Daher kam mir die Idee, diese Methode in einem Thread auszuführen. Da ich bisher noch nie mit Threads zu tun hatte, habe ich mich natürlich etwas angelesen, neben der Delphi-Hilfe unter anderem das
type
TfmMain = class(TForm) procedure FormCreate(Sender: TObject); private FObject : TComplexClass; end; implementation procedure TfmMain.FormCreate(Sender: TObject); begin FObject:= TComplexClass.Create(ip); if FObject.Ping then begin [...] end; end; ![]() ![]() Aber ein paar wichtige Sachen sind mir noch unklar:
Auch diesmal hoffe auf Aufklärung mittels der hier vertretenen Expertise :). Grüße Dalai |
AW: Anfängerfragen zu Threads (TThread)
Verstehe die Frage 1 nicht. Du schreibst doch Execute selber. Execute macht an sich überhaupt nichts.
Delphi-Quellcode:
procedure TMyThread.Execute;
var Dings: TDings; begin Dings := TDings.Create(); Dings.Bums(); end; |
AW: Anfängerfragen zu Threads (TThread)
Zitat:
Zitat:
Zitat:
Grüße Dalai |
AW: Anfängerfragen zu Threads (TThread)
Dann übergib an den Thread doch einfach nur per Property oder im Constructor die IP-Adresse des Ziel-Rechners. Und dann führst du im Thread den Ping aus und gibst das Ergebnis bspw. per Event zurück. Dann musst du auch beim Auslösen des OnTerminate Events des Threads nicht die Daten selber abholen sondern bekommst sie als Parameter vom eigenen Event geliefert.
|
AW: Anfängerfragen zu Threads (TThread)
Dein Hinweis war möglicherweise der Schubs in die richtige Richtung. Du meinst also etwa in der Art:
Delphi-Quellcode:
Und dann in TfmMain
type
TPingThread = class(TThread) private { Private-Deklarationen } FFB: TComplexClass; protected procedure Execute; override; public constructor Create(const AHost: string); destructor Destroy; override; property ReturnValue; end; constructor TPingThread.Create(const AHost: string); begin FreeOnTerminate:= True; FFB:= TComplexClass.Create(AHost); inherited Create(False); end; destructor TPingThread.Destroy; begin FFB.Free; inherited; end; procedure TPingThread.Execute; begin // Sleep nur zu Zwecken des Debugging Sleep(100); if Assigned(FFB) then ReturnValue:= Integer(FFB.Ping); end;
Delphi-Quellcode:
Das funktioniert. Zwei Sachen stören mich:
procedure TfmMain.FormCreate(Sender: TObject);
begin // Die Zuweisung von FHostName lasse ich mal mangels Relevanz weg; ist ein privates Attribut der Klasse FObject:= TComplexClass.Create(FHostName); PingThreadStart; end; procedure TfmMain.PingThreadStart; begin FPingThread:= TPingThread.Create(FHostName); FPingThread.OnTerminate:= PingThreadDone; end; procedure TfmMain.PingThreadDone(Sender: TObject); var Lsucc: Boolean; begin Lsucc:= Boolean(FPingThread.ReturnValue); if Lsucc then Self.Caption:= 'Connected to ' + FObject.HostName else MessageBox(Self.Handle, PChar(FObject.HostName + ' not available'), '', MB_OK or MB_ICONINFORMATION); end;
Grüße Dalai |
AW: Anfängerfragen zu Threads (TThread)
In der Art..
Warum muß die eierlegende Wollmilchsauklasse dem Thread bekannt sein? Der Thread hat eine (kleine) Aufgabe zu erledigen, und dabei sollte er sich auf seinen Hinterhof beschränken, auf dem sich aber auch niemand anders herum treiben sollte. Und wenn er fertig ist, dies dem Mainthread mit einem Postmessage bekannt geben. Gruß K-H |
AW: Anfängerfragen zu Threads (TThread)
Hi Dalai,
was heißt "vorzeitig terminieren"? Wenn du das Programm etwa mit dem Schließen X beendest? Wenn dem so sein sollte, dann müsste deine Anwendung einen Shutdown Prozess initiieren und alle noch laufenden Threads "sauber" beenden. Möglicherweise kann dann das Beenden der Anwendung auch ein paar Sekunden dauern. Einen Thread direkt wegschießen halte ich nicht für besonders gut und wüsste auch wenn ich ehrlich bin nicht wie ich das machen sollte. Ansonsten beachte noch den Hinweis von p80286. Ein Thread bearbeitet nur eine kleine Teilaufgabe und muss auch dementsprechend nur die Informationen bekommen die er zum Arbeiten benötigt. |
AW: Anfängerfragen zu Threads (TThread)
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Grüße Dalai |
AW: Anfängerfragen zu Threads (TThread)
Nach ein bisschen Umbau und der Nutzung nur jener Klasse, die wirklich nötig ist, sieht es nun so aus:
Delphi-Quellcode:
und in TfmMain weise ich das OnPingDone-Event statt OnTerminate zu. Das Speicherleck beim vorzeitigen Beenden ist etwas kleiner:
type
TPingThread = class(TThread) private FClient: TClient; FOnPingDone: TNotifyEvent; protected procedure Execute; override; public constructor Create(const AHost: string); destructor Destroy; override; property OnPingDone: TNotifyEvent read FOnPingDone write FOnPingDone; property ReturnValue; end; implementation constructor TPingThread.Create(const AHost: string); begin FOnPingDone:= nil; FreeOnTerminate:= True; FClient:= TClient.Create(AHost); FClient.Port:= 80; inherited Create(False); end; destructor TPingThread.Destroy; begin FClient.Free; inherited; end; procedure TPingThread.Execute; begin if Assigned(FClient) then ReturnValue:= Integer(FClient.IsAlive); if Assigned(FOnPingDone) then FOnPingDone(Self); end;
Code:
Kann man dagegen noch etwas tun? Ist zwar nicht besonders groß, aber stören tut's mich schon, und normalerweise räume ich den Krempel wieder auf, den ich erzeuge.
---------------------------
Unexpected Memory Leak --------------------------- An unexpected memory leak has occurred. The unexpected small block leaks are: 1 - 12 bytes: TObject x 1 21 - 28 bytes: AnsiString x 1 61 - 68 bytes: Unknown x 1 69 - 76 bytes: TPingThread x 1 93 - 100 bytes: TClient x 1 --------------------------- OK --------------------------- Grüße Dalai |
AW: Anfängerfragen zu Threads (TThread)
Sorry, falls der Eindruck entsteht, ich würde spammen, aber ich glaube, ich hab's. Außerdem fiel mir auf, dass OnTerminate mittels Synchronize gerufen wird, das selbstdefinierte Event OnPingDone aber nicht. Das hab ich gleich korrigiert, sonst gibt's später böse Fehler.
Thread:
Delphi-Quellcode:
Main:
type
TPingThread = class(TThread) private FClient: TClient; FOnPingDone: TNotifyEvent; procedure CallOnPingDone; protected procedure Execute; override; public constructor Create(const AHost: string); destructor Destroy; override; property OnPingDone: TNotifyEvent read FOnPingDone write FOnPingDone; property ReturnValue; end; procedure TPingThread.CallOnPingDone; begin if Assigned(FOnPingDone) then FOnPingDone(Self); end; constructor TPingThread.Create(const AHost: string); begin FOnPingDone:= nil; FreeOnTerminate:= True; FClient:= TClient.Create(AnsiString(AHost)); FClient.Port:= 80; inherited Create(False); end; destructor TPingThread.Destroy; begin FClient.Free; inherited; end; procedure TPingThread.Execute; begin if Assigned(FClient) then ReturnValue:= Integer(FClient.IsAlive); if NOT Terminated then Synchronize(CallOnPingDone); end;
Delphi-Quellcode:
Das gibt laut FastMM keine Lecks, der Destruktor des Threads wird durchlaufen, und alle drei Fälle (erreichbar, nicht erreichbar, vorzeitig terminiert) funktionieren. Falls jemand Einwände dagegen hat, immer her damit; ich lerne gern dazu (sofern ich's verstehe ;)).
type
TfmMain = class(TForm) private FObject : TComplexClass; FPingThread : TPingThread; FPingThreadAlive : Boolean; end; procedure TfmMain.FormCreate(Sender: TObject); begin FObject:= TComplexClass.Create(FHostName); PingThreadStart; end; procedure TfmMain.FormClose(Sender: TObject; var Action: TCloseAction); begin if FPingThreadAlive then begin FPingThreadAlive:= False; FPingThread.Terminate; end; end; procedure TfmMain.PingThreadStart; begin FPingThreadAlive:= True; FPingThread:= TPingThread.Create(FHostName); FPingThread.OnPingDone:= PingThreadDone; end; procedure TfmMain.PingThreadDone(Sender: TObject); var Lsucc: Boolean; begin FPingThreadAlive:= False; Lsucc:= Boolean(FPingThread.ReturnValue); if Lsucc then Self.Caption:= 'Connected to ' + FObject.HostName else MessageBox(Self.Handle, PChar(FObject.HostName + ' not available'), '', MB_OK or MB_ICONINFORMATION); end; Grüße Dalai |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:10 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