![]() |
Threads und Eventhandler
Hallo!
Ich mache gerade meine ersten Schritte in Multithreading und da klemmt es gerade dabei, Eventhandler richtig anzusprechen. Hier ein stark vereinfachtes Testprogramm, dass das Problem verdeutlichen soll. Soweit ich das verstehe hat der Thread trotz EnterCriticalSection keinen Zugriff auf die Eventhandler-Methodenzeiger der Instanz von TmyClass. Nur warum verstehe ich gerade nicht so recht. Da wäre ich für ein paar Tips dankbar. Um eine Diskussion gleich zu vermeiden: Ich verwende NOCH kein TThread weil das hier auf einem Demoprogramm aufbaut an dem ich mich erstmal orientieren will. Daher bitte keine "Mit TThread wär das nicht passiert"-Diskussion ;-) Wenn ich mal sicherer bin im Umgang mit Threads, dann mache ich auch eigene Konstruktionen in der Art. Stürmische Grüße Cody
Delphi-Quellcode:
unit Test;
interface uses System.Classes, Vcl.Controls, Winapi.Windows; type TmyClass = class(TObject) private FOnFailed: TNotifyEvent; FOnStarted: TNotifyEvent; protected procedure DoFailed; procedure DoStarted; public constructor Create; destructor Destroy; override; procedure Produce; property OnFailed: TNotifyEvent read FOnFailed write FOnFailed; property OnStarted: TNotifyEvent read FOnStarted write FOnStarted; end; TForm1 = class(TForm) procedure DoOnFailed(Sender: TObject); procedure DoOnStarted(Sender: TObject); procedure Form1Create(Sender: TObject); procedure Form1Destroy(Sender: TObject); procedure Button1Click(Sender: TObject); end; var FThreadId: DWord; implementation uses System.SysUtils; var CS: TRTLCriticalSection; myClass: TmyClass; { TmyClass } constructor TmyClass.Create; begin FStreamHandle := 0; FThreadId := 0; end; destructor TmyClass.Destroy; begin { .. } inherited; end; procedure TmyClass.DoFailed; begin if Assigned(FOnFailed) then begin // <-- FOnFailed = NIL **WARUM??** FOnFailed(Self); end; end; procedure TmyClass.DoStarted; begin if Assigned(FOnStarted) then begin // <-- FOnStarted = NIL **WARUM??** FOnStarted(Self); end; end; procedure TmyClass.Produce; var Dummy: Cardinal; Func: TThreadFunc; Status: Boolean; function _ThreadFunc: Integer; begin Result := 0; Status := MachIrgendwas; EnterCriticalSection(CS); try if Status then begin DoStarted; end else begin DoFailed; end; finally LeaveCriticalSection(CS); end; FThreadId := 0; end; begin if FThreadId = 0 then begin FThreadId := BeginThread(nil, 0, @_ThreadFunc, Nil, 0, Dummy); end; end; { TForm1 } procedure Form1Create(Sender: TObject); begin myClass := TmyClass.Create; myClass.OnFailed := DoOnFailed; myClass.OnStarted := DoOnStarted; end; procedure Form1Destroy(Sender: TObject); begin FreeAndNil(myClass); end; procedure TForm1.Button1Click(Sender: TObject); begin myClass.Produce; end; initialization InitializeCriticalSection(CS); finalization DeleteCriticalSection(CS); end. |
AW: Threads und Eventhandler
Deine _ThreadFunc ist eine lokale Funktion und keine TThreadFunc wie von BeginThread erwartet. Die Notwendigkeit des @-Operators um den Compiler zu besänftigen sollten schon ein Warnsignal gewesen sein, daß das vielleicht nicht ganz richtig sein könnte.
Delphi-Quellcode:
Du musst also eine globale Funktion mit dieser Signatur übergeben. In dem Parameter könntest du den Pointer auf die Objekt-Instanz mitgeben, womit du dann auf DoStarted und DoFailed zugreifen könntest (bei geeigneter Sichtbarkeit). Leider bleibt dir der Zugriff auf die lokale Variable Status aber trotzdem verwehrt. Das ist aber auch gut so, da diese ja nach dem Verlassen von Produce auch nicht mehr existiert (und dann läuft dein Thread vermutlich noch).
type
TThreadFunc = function(Parameter: Pointer): Integer; ... function BeginThread(SecurityAttributes: Pointer; StackSize: LongWord; ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord; var ThreadId: TThreadID): THandle; Ich verstehe aber wirklich nicht, warum du den definitiv schwierigsten Weg wählst, um dich mit Threading zu beschäftigen, anstatt eine wenigstens halbwegs brauchbare fertige Kapselung zu verwenden. Das obige Problem ist eine direkte Folge dieser Herangehensweise. Wollte man das auch rein mit Delphi Bordmitteln erledigen, wären Anonyme Methoden und TThread oder TTask die bessere Wahl. Ist mir auch egal, ob du das nun hören willst oder nicht. |
AW: Threads und Eventhandler
Wenn man schon auf die Nase fällt, dann wenigstens mit ordentlich Anlauf :-D
Wie gesagt, das basiert auf einer (für meine Einsteiger-Verhältnisse) relativ komplexen Demo. Diese wurde offensichtlich für C++ gestrickt und dann quasi 1:1 für Delphi angepasst. Ich habs jetzt auf TThread umgestrickt. Dort habe ich aber ähnliche Probleme. Variablen, die im Interface-Private des TThread-Objektes definiert sind, ändern sich völlig willkürlich. Deklariere ich sie Unit-global im Interface-Teil, dann funktioniert es, obwohl ich KEIN CriticalSection verwende (was ich eigentlich erwartet hätte dass dann umso mehr Probleme auftauchen müssten). Threadprogrammierung ist schon sehr verwirrend ^^ Ein andermal mehr, morgen ist wieder Arbeit angesagt... |
AW: Threads und Eventhandler
Zitat:
|
AW: Threads und Eventhandler
Zitat:
![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:51 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