![]() |
Delphi-Version: 10.3 Rio
Verhalten von TFileStream/TBufferedFileStream bei Crash
Hallo zusammen,
ich möchte Log-Files bei Crash aufnehmen, und damit möglichst nah an den Crash-Punkt herankommen. Das Ganze sollte auch auf allen Platformen laufen, aber mir geht es erstmal um eine grundsätzliche Frage. Die Klassen hängen wie folgt zusammen:
Delphi-Quellcode:
Zum Logging halte ich jetzt einen globalen TFileStream offen, in dem die Logs geschrieben werden.
TStream = class(TObject);
//<-- TStream hat kein explizites Destroy THandleStream = class(TStream) protected FHandle: THandle; //<-- hat kein explizites Destroy, hält nur den Handle TFileStream = class(THandleStream) destructor TFileStream.Destroy; begin if FHandle <> INVALID_HANDLE_VALUE then FileClose(FHandle); inherited Destroy; end; //<-- Handle wird hier entsorgt und womöglich erst jetzt in ein physikalisches File geschrieben TBufferedFileStream = class(TFileStream) destructor TBufferedFileStream.Destroy; begin SyncBuffer(False); //<-- Der Memory-Buffer wird in das File geschrieben FreeMem(FBuffer, FBufferSize); inherited Destroy; end; //<-- Buffer wird erst geschrieben, und dann mit inhertied in ein physikalisches File geschrieben TFileStream Wenn jetzt irgendwo ein Crash auftritt, wie verhält sich das noch offene File ? Wer ruft TFileStream.Destroy auf, ist sichergestellt das sich alle Scopes korrekt abbauen ? Ist es irgenwie garantiert (Delphi/jeweiliges OS) dass das offene File-Handle trotz Crash geschlossen wird ? Wie verhält sich der OS-Cache in einem solchen Fall, gehen die Daten im Cache verloren (Unterschiede Win/iOS/Android/Mac ...) ? Kann es sein dass das physikalische File im System offen bleibt (Unterschiede Win/iOS/Android/Mac ...) ? TBufferedFileStream Wenn ich jetzt statt TFileStream TBufferedFileStream benutze: Es kommt noch das FlushBuffer in die Ablaufkette hinzu. Wird das TBufferedFileStream.Destroy garantiert aufgerufen, oder kann der Buffer verlorengehen ? Meine Vermutung ist das es sowohl bei TFileStream als auch TBufferedFileStream Datenverluste geben kann, und der letzte Stand verloren gehen kann. Gibt es vielleicht einen versteckten Mechanismus (Exception-Handler) in Delphi, der den Datenverlust verhindern könnte. Ist es jetzt besser TFileStream oder TBufferedFileStream für das Loggen zu Verwenden ? Sorry, viele Fragen, aber vielleicht gibt es ja eine einfache Antwort :stupid: |
AW: Verhalten von TFileStream/TBufferedFileStream bei Crash
Läuft denn das Logging im gleichen Thread, der dann hängen bleibt/abstürzt?
Ein mir bekanntes Vorgehen ist bspw. das Logging über eine Queue in einen eigenen Thread zu machen. Da könntest du zum Beispiel explizit FlushBuffer aufrufen, wenn alle anstehenden Log-Meldungen im BufferedFileStream sind. Wenn der VCL-Mainthread dann hängen bleibt, hat man zumindest noch die letzten Logmeldungen weggeschrieben. |
AW: Verhalten von TFileStream/TBufferedFileStream bei Crash
Zitat:
Der Zugriff darauf kann natürlich durch CS abgesichert werden, und sollte nicht das Problem sein. Es könnte wohl ein globaler Exception-Handler eingebaut werden, um das abzusichern.
Delphi-Quellcode:
Aber die Frage ist was passiert eigentlich wenn der eben nicht da ist.
Application.OnException := MyExceptionHandler;
Schliesst Delphi in seinem Exception-Handler alle offenen Files, oder macht dass das OS nach Beenden einer App ? Worauf kann man sich verlassen, und worauf nicht ? |
AW: Verhalten von TFileStream/TBufferedFileStream bei Crash
Die Applikation (Mainthread) kann ja einfach so hängen bleiben, ohne das eine Exception aufgetreten ist.
|
AW: Verhalten von TFileStream/TBufferedFileStream bei Crash
Ok, wenn aber eine Exception kommt wird dann aufgeräumt ?
Es geht hier mehr um iOS, ist aber generell die Frage wie Exception mit offenen Files umgehen. Natürlich gibt es auch verschiedene Exceptions (Div0, Speicherfehler, AV, ...), ich denke mache sind kritisch für das File-Sichern, manche nicht. |
AW: Verhalten von TFileStream/TBufferedFileStream bei Crash
Zitat:
Zitat:
Wird wohl da so ähnlich sein. Das von dir gewünschte Verhalten musst du selber implementieren, dass heißt im TApplication.OnException selber dafür sorgen, dass deine Logging-Komponente sauber verarbeitet und ggf. beendet wird. Es gibt kein Automatismus. Wobei grundsätzlich etwas schief läuft, wenn so Sachen wie Div0-Exceptions bis soweit oben hochbubbeln. Wirklich sicher bist du nur mit einer abgesetzten Lösung (siehe oben), weil Anwendungskritische Vorfälle auch ohne Exceptions auftreten können (Deadlock, Endlosschleifen, hartes Terminieren durch das Betriebssystem). |
AW: Verhalten von TFileStream/TBufferedFileStream bei Crash
Bei TFileStream kann nichts verloren gehen, selbst wenn man vergisst das Streamobjekt freizugeben.
Es wurden ja bereits alle Schreibvorgänge ausgeführt und warten vielleicht noch im WindowsFileCache, bis es auf der Platte landet. Spätestens wenn das Programm dann beendet wird, schließt Windows das FileHandle und die Datei ist entgültig zu Und so lange nicht das komplette Windows abstürzt, wird auch irgendwann das noch auf die Platte geschrieben, was noch im FileCache hing. Beim TBufferedFileStream ist es wie mit dem guten alten ![]() ![]() |
AW: Verhalten von TFileStream/TBufferedFileStream bei Crash
Zitat:
Ich versuche im Moment mit einem class destruktor zu Testen, der sollte so einigermaßen am Schluss gefeuert werden (hoffentlich auch beim Crash).
Delphi-Quellcode:
Sehe ich das '<==== FILE BUFFER DESTROYED' im Log hats funktioniert.
class destructor TLog_Base.Destroy;
begin DestroyFileBuffer; end; class procedure TLog_Base.DestroyFileBuffer; begin if Assigned( FFileStream ) then begin SendViaFile( '<==== FILE BUFFER DESTROYED' ); FFileStream.FlushBuffer; FFileStream.Free; end; end; So weiss ich wenigstens ob ich bis zum ende gelogged habe. |
AW: Verhalten von TFileStream/TBufferedFileStream bei Crash
Wenn das Programm hängen bleibt und vom System oder Taskmanager abgeschossen wird (TerminateProcess), weil es nicht mehr reagiert, dann wird dieser Code nicht ausgeführt.
Knalles es im Programm, aber es kann sich noch "ordentlich" beenden, dann ja. |
AW: Verhalten von TFileStream/TBufferedFileStream bei Crash
In der mORMot Library Unit SynLog.pas findest du umfangreiche Funktionen zum Loggen. Vielleicht kannst du in der Unit für dein eigenes Logging einige Anregungen finden. Die ausführliche Hilfe ist hier:
![]() Bis bald... Thomas |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:45 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