![]() |
Execption innerhalb AnonymousThread behandeln
Hallo Zusammen,
ich versuche gerade die Methode GetGruppen in einem AnonymusThread zu packen. Dabei stellen sich mir eine Menge Frage. Die Methode GetGruppen ist in einem Adroid Mobile Projekt und ruft über die Methode DataModule1.ServerMethods1Client.GetGruppen ein Dataset aus einem DataSnap Server und speichert das Ergebnis in ein lokales JASONDataSets Object. Das dürfte im Thread noch keine Probleme machen das keine Aktionen Objkte auf dem MainThread tangieren. Die Methode UpdateGruppenNames jedoch packt das JASONDataSets in einer FDMemTable die auf der MainForm liegt. Mir ist bekannt dass nur der MainThread auf Objekte der Form zugreifen darf. Ist jetzt eine FDMemTable ebenfalls davon betroffen oder nur Objekte die etwas anzeigen wie z.B.: TLabel, TListView u.s.w.? Die nächste Frage, was ist mit der Exception innerhalb des Threads, darf ich die ShowMessageFmt werfen oder muss das in einem TThread.Synchronize erfolgen? Ohne Thread
Delphi-Quellcode:
procedure TfrMobileMain.GetGruppen;
var LDataSetList: TFDJSONDataSets; begin try //vom DataSnap Server ein DataSet abrufen LDataSetList := DataModule1.ServerMethods1Client.GetGruppen; //das DataSet in die MemTable packen UpdateGruppenNames(LDataSetList); except on E: TDSRestProtocolException do HandleRestException(DataModule1.DSRestConnection1, 'Get Gruppen error', E); on E: Exception do ShowMessageFmt('Fehler: %s',[E.Message]); else raise; end; end; Mit Thread
Delphi-Quellcode:
Gruß Kostas
procedure TfrMobileMain.GetGruppenThreaded;
begin TThread.CreateAnonymousThread(procedure () var LDataSetList: TFDJSONDataSets; begin try LDataSetList := DataModule1.ServerMethods1Client.GetGruppen; UpdateGruppenNames(LDataSetList); // TThread.Synchronize (TThread.CurrentThread, // procedure () // begin // end); except on E: TDSRestProtocolException do HandleRestException(DataModule1.DSRestConnection1, 'Get Gruppen error', E); on E: Exception do ShowMessageFmt('Fehler: %s',[E.Message]); else raise; end; end).Start;{TThread} end; |
AW: Execption innerhalb AnonymousThread behandeln
Eigentlich sollte doch klar sein, wie man das macht?
Zugriffe auf die VCL müssen immer synchronisiert werden, also wieso wird das in der Exceptionbehandlung nicht gemacht? TThread besitzt standardmäßig keinerlei Exception-
Delphi-Quellcode:
Auswertung.
Behandlung
Eine Behandlung ist drin, da Exceptions, welche bis ins System durchrauschen, den Prozess abschießen. Exceptions im TThread.Execute werden abgefangen und sind über TThread.FatalException auswertbar, aber das muß man selber machen. (z.B. im TThread.OnTerminate) Entweder du synchronisierst in deinem Try-Except die VCL-Zugriffe, oder du läßt dein Try-Except komplett weg und benutzt das Try-Except der RTL, indem du z.B. ein OnTerminate implementierst und da anhängst. Der Vorteil am OnTerminate ist, daß die RTL diesen Aufruf bereits in den MainThread synchronisiert.
Delphi-Quellcode:
Alternativ natürlich nicht ohne die Synchronisierung.
type
TMyThreadHelper = class abstract class procedure DoTerminate(Sender: TObject); end; class procedure TMyThreadHelper.DoTerminate(Sender: TObject); begin if Assigned(TThread(Sender).FatalException) then if TThread(Sender).FatalException is TDSRestProtocolException then HandleRestException(DataModule1.DSRestConnection1, 'Get Gruppen error', Exception(TThread(Sender).FatalException)) else //ShowMessageFmt('Fehler: %s, [Exception(TThread(Sender).FatalException).Message]); //Application.HandleException(TThread(Sender).FatalException); ShowException(TThread(Sender).FatalException, nil); // such dir was aus end; with TThread.CreateAnonymousThread( procedure var LDataSetList: TFDJSONDataSets; begin LDataSetList := DataModule1.ServerMethods1Client.GetGruppen; UpdateGruppenNames(LDataSetList); end) do begin OnTerminate := TMyThreadHelper.DoTerminate; Start;{TThread} end; Eventuell auch nur um das ShowMessage, wenn das HandleRestException threadsave ist.
Delphi-Quellcode:
Ohne Behandlung von FatalException war dein raise etwas umsonst, da es quasi im Nirgendwo verpufft.
except
on E: Exception do // alternativ ginge auch ein var E: TObject; und E := ExceptObject; TThread.Synchronize(TThread.CurrentThread, procedure begin if E is TDSRestProtocolException then HandleRestException(DataModule1.DSRestConnection1, 'Get Gruppen error', Exception(E)) else //if E is Exception then ShowMessageFmt('Fehler: %s', [Exception(E).Message]); //else // {nix}; end); end; Und in Delphi sind (standardmäßig) alle Exceptions vom Typ Exception, so daß es vermutlich eh nicht ausgelöst wird, aber schaden kann der Code auch nichts. |
AW: Execption innerhalb AnonymousThread behandeln
Zitat:
Anonyme Threads halte ich für ein Problem in sich - in namentlich deklarierten Threads hat man die räumliche Trennung im Code (eigene Klasse, eigene Datei) und wird gezwungen, sich Gedanken über threadsichere Schnittstellen zu machen. (Nachtrag: ich habe gerade in einem anderen Thread gelesen, anonyme Funktionen könnten threadsicher auf lokales zugreifen? Dann würde obiges nicht mehr ganz stimmen) |
AW: Execption innerhalb AnonymousThread behandeln
Bevor Emba sich das mit dem CreateAnonymousThread abgeguckt hat, hatte ich mir schon länger eine "starte (anonyme) Methode als Thread"-Funktion gebaut.
Nur mit einem Unterschied: * der Thread bekommt einen Namen (NameThreadForDebugging), damit man ihn im Debugger besser erkennt, weiß wo er her kommt und somit schnell sieht was er macht * und das DoTerminate wurde überschrieben, welches eine Exceptionmeldung in den Hauptthread schiebt (oder alternativ ins Log) |
AW: Execption innerhalb AnonymousThread behandeln
Zitat:
Es greift jedoch auf keinerlei visuelle Komponenten zu. Was ich noch nicht verinnerlicht habe, kann ich auf ein TFDMemTable aus einem Thread- anonym oder nicht, sei mal dahingestellt, zugreifen oder muss auch dieser Teil in einem Synchronize Block.
Delphi-Quellcode:
TThread.Synchronize (TThread.CurrentThread,
procedure () begin //Zugriff auf die FDMemTable. end); |
AW: Execption innerhalb AnonymousThread behandeln
Herzlichen Danke himitsu,
ich werde deine Methode verwenden mit dem DoTerminate. |
AW: Execption innerhalb AnonymousThread behandeln
[QUOTE=Kostas;1274294]
Zitat:
|
AW: Execption innerhalb AnonymousThread behandeln
Man muss doch nur schauen was man verwendet- Ein "Datenmodul" ist ja an sich nur eine Gruppierung von mehreren "Komponenten"- Mit VCL, FMX oder sonst was hat das das doch überhaupt nichts mehr zu tun.
Wenn man z.B. ein "Datenmodul" hat das in irgendeiner Datenbank (z.B. mittels FireDAC) wühlen soll, FireDAC meint die Benutzung aus mehreren Threads sei in Ordnung, dann kann ich mein Datenmodul doch auch so benutzen. |
AW: Execption innerhalb AnonymousThread behandeln
Hallo himitsu,
die Methode HandleRestException benötigt als zweiten Parameter ein String als Fehlermeldung. Ich habe die DoTerminate erweitert um den Parameter "ErrorMsg". Ob das so geht bin ich mir nicht sicher. Wenn es so machbar ist, müsste ich beim Aufruf den Sender angeben. Ohne den zusätzlichen Parameter "ErrorMsg" musste der Sender nicht übergeben werden da es ein TNotifyEvent ist. Hast du mir bitte noch ein kleinen Hinweis?
Delphi-Quellcode:
class procedure TMyThreadHelper.DoTerminate(ErrorMsg:string; Sender: TObject); <<so geht's nicht
begin if Assigned(TThread(Sender).FatalException) then if TThread(Sender).FatalException is TDSRestProtocolException then HandleRestException(DataModule1.DSRestConnection1, ErrorMsg, TDSRestProtocolException(TThread(Sender).FatalException)) else ShowException(TThread(Sender).FatalException, nil); end;
Delphi-Quellcode:
OnTerminate := TMyThreadHelper.DoTerminate('Get Gruppen error', ???);
|
AW: Execption innerhalb AnonymousThread behandeln
Beim Überschreiben virtueller Methoden, müssen die Parameter natürlich gleich bleiben.
* Entweder eine böse globale Variable, * das TThread abgleeitet, aber dann müsste man das CreateAnonymusThread selbst schreiben, um dort seine eigene TThread-Klasse zu erstellen (bei mir ist dort das "Start" auch gleich mit integriert) * TMyThreadHelper als Instanz mit Feld/Variable und DoTerminate als Methode und nicht als Klassen-Methode * oder bei eigenen Exceptions kann man ZusatzInfos auch im Exceptions-Objekt mitgeben. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:48 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