AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Execption innerhalb AnonymousThread behandeln

Execption innerhalb AnonymousThread behandeln

Ein Thema von Kostas · begonnen am 29. Sep 2014 · letzter Beitrag vom 30. Sep 2014
Antwort Antwort
Kostas

Registriert seit: 14. Mai 2003
Ort: Gerstrhofen
906 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

Execption innerhalb AnonymousThread behandeln

  Alt 29. Sep 2014, 23:55
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:
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;
Gruß Kostas
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
38.915 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Execption innerhalb AnonymousThread behandeln

  Alt 30. Sep 2014, 05:57
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-Behandlung Auswertung.

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:
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;
Alternativ natürlich nicht ohne die Synchronisierung.
Eventuell auch nur um das ShowMessage, wenn das HandleRestException threadsave ist.
Delphi-Quellcode:
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;
Ohne Behandlung von FatalException war dein raise etwas umsonst, da es quasi im Nirgendwo verpufft.
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.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (30. Sep 2014 um 06:00 Uhr)
  Mit Zitat antworten Zitat
CCRDude

Registriert seit: 9. Jun 2011
664 Beiträge
 
FreePascal / Lazarus
 
#3

AW: Execption innerhalb AnonymousThread behandeln

  Alt 30. Sep 2014, 08:22
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.
Ich kenne jetzt das Framework nicht, aber ist DataModule1 nicht ein Objekt aus dem Mainthread?

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)

Geändert von CCRDude (30. Sep 2014 um 08:27 Uhr) Grund: Zweiter Teil Begrüdung
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
38.915 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Execption innerhalb AnonymousThread behandeln

  Alt 30. Sep 2014, 08:56
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)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (30. Sep 2014 um 08:59 Uhr)
  Mit Zitat antworten Zitat
Kostas

Registriert seit: 14. Mai 2003
Ort: Gerstrhofen
906 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Execption innerhalb AnonymousThread behandeln

  Alt 30. Sep 2014, 09:57
Ich kenne jetzt das Framework nicht, aber ist DataModule1 nicht ein Objekt aus dem Mainthread?

(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)
Eigentlich hast du Recht. Das DataModule1 läuft auf dem Mainthread und beinhaltet die Kommunikation zu DataSnapServer.
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);
  Mit Zitat antworten Zitat
Kostas

Registriert seit: 14. Mai 2003
Ort: Gerstrhofen
906 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: Execption innerhalb AnonymousThread behandeln

  Alt 30. Sep 2014, 09:59
Herzlichen Danke himitsu,

ich werde deine Methode verwenden mit dem DoTerminate.
  Mit Zitat antworten Zitat
CCRDude

Registriert seit: 9. Jun 2011
664 Beiträge
 
FreePascal / Lazarus
 
#7

AW: Execption innerhalb AnonymousThread behandeln

  Alt 30. Sep 2014, 10:33
[QUOTE=Kostas;1274294]
Das DataModule1 läuft auf dem Mainthread und beinhaltet die Kommunikation zu DataSnapServer.
Es greift jedoch auf keinerlei visuelle Komponenten zu.
Ist das relevant? Klar, bekannt ist "vcl = nicht threadsafe". Aber den Umkehrschluß "nicht vcl = threadsafe" kann man daraus nicht folgern! Im Gegenteil, alles, was nicht explizit threadsicher ist, sollte aus Vorsicht erstmal nicht als solches betrachtet werden. Fehler treten sonst manchmal wirklich sehr willkürlich scheinend auf, manchmal erst viel später.
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
5.784 Beiträge
 
Delphi 10 Seattle Enterprise
 
#8

AW: Execption innerhalb AnonymousThread behandeln

  Alt 30. Sep 2014, 11:00
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.
  Mit Zitat antworten Zitat
Kostas

Registriert seit: 14. Mai 2003
Ort: Gerstrhofen
906 Beiträge
 
Delphi 10 Seattle Enterprise
 
#9

AW: Execption innerhalb AnonymousThread behandeln

  Alt 30. Sep 2014, 11:02
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;

OnTerminate := TMyThreadHelper.DoTerminate('Get Gruppen error', ???);
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
38.915 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Execption innerhalb AnonymousThread behandeln

  Alt 30. Sep 2014, 11:07
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.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (30. Sep 2014 um 11:10 Uhr)
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:44 Uhr.
Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf