Einzelnen Beitrag anzeigen

berens

Registriert seit: 3. Sep 2004
441 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Sind alle Thread Variablen in OnTerminate threadsicher?

  Alt 24. Feb 2025, 15:13
Achja, das wäre natürlich auch eine einfachere Variant die Werte zurückzugeben. Ich nehme an, du meinst es beispielhaft so?
Delphi-Quellcode:
type
  // Definition des Events mit allen relevanten Parametern
  TTestCompleteEvent = procedure(Sender: TObject; const ResultText: string; AllesOk: Boolean;
                                 ScreenWidth, ScreenHeight: Integer;
                                 ScreenDimensionMismatch, Vollbild: Boolean;
                                 CurrentMonitor: Integer) of object;

  TTestThread = class(TThread)
  private
    FOnTestComplete: TTestCompleteEvent;
    FResultText: string;
    FAllesOk: Boolean;
    procedure DoNotifyTestComplete;
  protected
    procedure InitializeVariabels; virtual;
    procedure Execute; override;
  public
    constructor Create;
    property OnTestComplete: TTestCompleteEvent read FOnTestComplete write FOnTestComplete;
  end;

procedure TTestThread.DoNotifyTestComplete;
begin
  if Assigned(FOnTestComplete) then
// Hier mit Dummy-Werten
    FOnTestComplete(Self, FResultText, FAllesOk, 123, 456, False, True, 1);
end;

Im realen Programm für den Endkunden habe ich mehrere "Selbsttests", die beim Programmstart laufen sollen. Thematisch haben diese Selbsttests relativ wenig miteinander zu tun: Der eine holt den freien Festplattenspeicher, der andere überprüft in der Datenbank-Tabelle, ob ungültige Zeitbezüge vorhanden sind, der nächste ob in der Registry unerwartete Werte stehen etc.

Aktuell läuft alles nacheinander, was sich im Laufe der Zeit immer weiter "aufschaukelt", und -je nach Netzwerkgeschwindigkeit- beim Programmstart zwischen 1-2 Sekunden bis zu mehreren Minuten brauchen kann, wenn der Kunde das Programm über eine Bambus-VPN-Leitung startet. Das kann so nicht weitergehen. Ich muss diese ganzen Tests in Threads packen. Das Programm kann/darf auch mit ungültigen Werten starten, die der Selbsttest eigentlich erst finden/beheben soll - das ist kein Problem, denn auch wenn sie beim Programmstart nach dem alten Verfahren hintereinander laufen, wird der Benutzer nur benachrichtigt.

Die Idee ist also, dass alle Tests erzeugt werden, die Testroutine wird über den Thread laufen gelassen (Threadsicherheit bei Datenbankabfragen kommt nun hinzu, CoInitialize etc.!), und sobald fertig wird im GUI beim entsprechenden Menüpunkt ein grüner Haken oder ein rotes X angezeigt. Die Tests selbst müssen aber (je nach Test) Werte aus dem Thread anzeigen können, damit ich dem Benutzer auch zeigen kann, "was genau" nicht simmt.

Wenn z.B. die Bildschirmauflösung sich von dem Wert in der Datenbank unterscheidet (es gibt eine Bedingung, wann das relevant ist), kommt eine Info an den Benutzer. Er kann nun die Auflösung in der Datenbank auf diesen (oder einen anderen) Wert ändern (neue Auflösung in die Datenbank schreiben; hat nix mit Thread zu tun), und den Test erneut laufen lassen. Da der Thread eh auf die DB zugreift, sagt er halt nicht nur "Auflösung richtig: Ja/Nein", sondern gibt mir auch die Auflösung, damit ich sie dem Benutzer im GUI anzeigen lassen kann, ohne sie *nochmals* auslesen zu lassen. Nach dem Ändern der Werte läuft der Thread erneut (Selbsttest), und beim OnTestComplete werden dann die Werte in den Edit-Feldern wieder aktualisiert.

Damit kann erstmal das Programm starten, die Haken für "Ok" oder die X für "Warnung/Fehler" ploppen dann im Menü so nach und nach bei den einzelnen Punkten davon als Grafik auf. Zumindest reagiert das Program in dieser Zeit auf Benutzereingaben.

---

Da mit Threads sehr viel Unglücke passieren können, die man beim Entwickeln nicht unmittelbar sieht (Arbeiten mit TAdoConnection ohne CoInitialize klappt meistens im DebugModus, und ohne Debugger in 70% der Fälle, aber nicht immer - für diesen und ähnliche Fehler benötigt man Erfahrung und Hintergrundwissen, was ich -in Bezug auf Threads- nicht soooo sicher habe, dass ich mich da jetzt munter in Gefilden bewegen Wollen würde, die dann weitere Probleme verursachen.

> Brauchst du wirklich eine eigene Klasse dafür oder hast du das genommen, weil du TThread nur als abgeleitete Klasse kennst?
Ich nehme an, du redest hier von anonymen Methoden/Threads? ChatGPT schlägt das hier vor, und das würde das Thema ja um den Faktor 100 vereinfachen:
Delphi-Quellcode:
TThread.CreateAnonymousThread(
  procedure
  var
    ResultText: string;
    AllesOk: Boolean;
    ScreenWidth, ScreenHeight: Integer;
    ScreenDimensionMismatch, Vollbild: Boolean;
    CurrentMonitor: Integer;
  begin
    // Beispielhafte Berechnung
    ScreenWidth := 1920;
    ScreenHeight := 1080;
    Vollbild := True;
    CurrentMonitor := 1;
    ScreenDimensionMismatch := (ScreenWidth <> Screen.Width) or (ScreenHeight <> Screen.Height);
    AllesOk := True;
    ResultText := 'Test abgeschlossen!';

    // Synchronisieren mit Hauptthread und direkt Callback aufrufen
    TThread.Synchronize(nil,
      procedure
      begin
        TestAbgeschlossen(nil, ResultText, AllesOk, ScreenWidth, ScreenHeight,
                          ScreenDimensionMismatch, Vollbild, CurrentMonitor);
      end);
  end
).Start;
Wäre das in etwa auch dein Vorschlag?
Delphi 10.4 32-Bit auf Windows 10 Pro 64-Bit, ehem. Delphi 2010 32-Bit auf Windows 10 Pro 64-Bit
  Mit Zitat antworten Zitat