AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi Ursache für hängende Applikation herausfinden
Thema durchsuchen
Ansicht
Themen-Optionen

Ursache für hängende Applikation herausfinden

Ein Thema von Bodenseematze · begonnen am 29. Jan 2024 · letzter Beitrag vom 27. Feb 2024
Antwort Antwort
Seite 2 von 4     12 34      
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.572 Beiträge
 
Delphi 11 Alexandria
 
#11

AW: Ursache für hängende Applikation herausfinden

  Alt 29. Jan 2024, 17:29
Das sollte klar sein, aber zur Sicherheit frage ich einfach mal. Du greifst im Thread nicht auf irgendwelche VCL-Komponenten zu, oder?

Und interessant wäre der komplette MadExcept Bericht, denn wenn da ein Deadlock im Spiel ist, braucht man die Stacktraces aller Threads. Du kannst den ja zensieren oder nur privat schicken.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Bodenseematze

Registriert seit: 10. Jul 2023
68 Beiträge
 
#12

AW: Ursache für hängende Applikation herausfinden

  Alt 30. Jan 2024, 10:09
Das sieht dann wirklich so aus, als würde sich in genau diesem Programm irgendwas "verstubbeln".
Ja
Wenn alles in allen Programmen gleich ist, vom Quelltext (der betroffenen Routine(n)), über den Rechner bis zur Datenbank über die Freigaben und alle weiteren Resourcen, da müsste man dann wohl mal in die Source schauen können, um Hilfestellung geben zu können.
Der Quelltext ist derselbe, die Datenbank ist die selbe und der pronzipielle Ablauf für den Fehlerfall sind gleich - die Programme kopieren allerdings unterschiedliche Dateien (aus dem selben lokalen Quellverzeichnis in ein jeweils selber generiertes temp. lokales Verzeichnis)...

Mit den Quellen ist das so eine Sache - mal abgesehen davon, dass die Quellen wohl etwas zu viel wären, darf ich diese nicht so ohne weiteres (komplett) rausgeben.
Und nur Teile bringt vermutlich nicht allzu viel...

Wie lange "hängt" das Programm dann? Kommt irgendwann eine Meldung oder tut sich irgendwann etwas?
Wenn ich Freeze-Erkennung in MadExcept nicht einschalte, hängt das Programm "ewig".

- Endlosschleife irgendwo
Ich denke, das hätte ich über MadExcept gesehen...
- Dialog oder Fenster im Hintergrund oder außerhalb des Bildschirms
Um solche Dinge auszuschließen habe ich extra beim Kopieren die Flags (NoConfirm, NoGui, etc.) entfernt - aber ausschließen kann ich das natürlich nicht.

- warten auf ein timeout (MSSQL Server und Locks!)
Das will ich natürlich nicht ausschließen, habe aber bereits auf dem SQL-Server mal mitgetraced und nichts auffälliges gefunden.
- rekursion ohne ende
Auch das müsste ich eigentlich bei der MadExcept "Freeze-Erkennung" gesehen haben....

Das sollte klar sein, aber zur Sicherheit frage ich einfach mal. Du greifst im Thread nicht auf irgendwelche VCL-Komponenten zu, oder?
Nicht, dass ich wüßte

Und interessant wäre der komplette MadExcept Bericht, denn wenn da ein Deadlock im Spiel ist, braucht man die Stacktraces aller Threads. Du kannst den ja zensieren oder nur privat schicken.
Ich schicke ihn Dir mal per privater Mail...
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.993 Beiträge
 
Delphi 12 Athens
 
#13

AW: Ursache für hängende Applikation herausfinden

  Alt 30. Jan 2024, 10:25
Mit Debugger starten, oder beim Hängen den Debugger anhängen,
auf "Pause" gedrückt (falls nicht automatisch geschehen)
und dann im Stacktrace des MainThreads nachsehn.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Kas Ob.

Registriert seit: 3. Sep 2023
344 Beiträge
 
#14

AW: Ursache für hängende Applikation herausfinden

  Alt 30. Jan 2024, 11:15
Hi,

Das sollte klar sein, aber zur Sicherheit frage ich einfach mal. Du greifst im Thread nicht auf irgendwelche VCL-Komponenten zu, oder?
Nicht, dass ich wüßte
But you are !
Zitat:
7736FF74 +0044 ntdll.dll RtlEnterCriticalSection
4002FE37 +0007 rtl70.bpl Classes ThreadList.LockList
01984929 +015D vcl70.bpl Controls TWinControl.PaintControls
See, there is no difference if you are accessing the thread itself from VCL or blocking to access something shared with a thread.

Suggestion, but i will use an example for language barrier (may be will be readable):
you a thread that perform disk operations, these operations or tasks are in in lockable thread safe list, your VCL components need to have a visual report or just output something, then the reason is right to lock within VCL events to read these tasks and their result,
now the problem is if the thread is locking on the task from beginning of performing the task (whatever the task, copy, move, write, upload ...) these tasks are I/O, so instead of the threads locking on the operation within the list, just make it lock and extract the needed operation context without performing any real work, while locking you do mark the task as in pending or processing, then release that task list,
only after that let the thread perform the operation ,after finishing or needing to update, lock again and update the result.
this will not block the VCL and UI will stay responsive all the time.
Now to capture the failure or taking-so-long operation (file, network, calculating, whatever...) put in the VCL a hidden or hard to miss click button or menu to intentionally raise an exception, MadExcept like Eurekalog can capture all the threads stack hence you will have better idea where to look.
Kas
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
1.925 Beiträge
 
Delphi 12 Athens
 
#15

AW: Ursache für hängende Applikation herausfinden

  Alt 30. Jan 2024, 16:06
Also es gibt das manchmal das Systemaufrufe einfach nicht zurrückkehren...
Hatte das mal mit diesem hier
SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE,0, Longint(@Device));//Registryänderung soll vom System gelesen werden. Der StandardDrucker wurde in der Registry geändert und durch diesen REFRESH wird die Änderung wirksam...
Das problem ist das bei einzelnen Rechnern dieser Refresh nicht mehr zurrück kam...
Es gab auch keine Fehlermeldung...Es war so als ob dieses SendMessage einfach für dauerte...
Leider gab as keine Lösung außer es nichtmehr so zu machen.
Andreas
Monads? Wtf are Monads?
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.572 Beiträge
 
Delphi 11 Alexandria
 
#16

AW: Ursache für hängende Applikation herausfinden

  Alt 30. Jan 2024, 16:16
Leider gab as keine Lösung außer es nichtmehr so zu machen.
SendMessage sollte man ausschließlich verwenden, wenn es wichtig ist, dass die Nachricht abgearbeitet ist, bevor der nachstehende Code ausgeführt wird (z.B. wegen des Rückgabewerts). Ansonsten sollte man immer PostMessage verwenden, das nicht hängen bleibt, egal was bei der Abarbeitung passiert.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.993 Beiträge
 
Delphi 12 Athens
 
#17

AW: Ursache für hängende Applikation herausfinden

  Alt 30. Jan 2024, 16:21
Ja, es ist nicht so leicht, die MessageQueue voll zu bekommen,
aber bei PostMessage sollte man auch aufpassen, ob es wirklich in der Queue landet.
Nicht dass die Message verschwiendet und somit nie verarbeitet wird.

Statt PostMessage könnte man auch TThread.Queue bzw. ForceQueue benutzen.
(quasie wie der Unterschied zwischen SendMessage und TThread.Syncronize)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.572 Beiträge
 
Delphi 11 Alexandria
 
#18

AW: Ursache für hängende Applikation herausfinden

  Alt 30. Jan 2024, 16:28
aber bei PostMessage sollte man auch aufpassen, ob es wirklich in der Queue landet.
Nicht dass die Message verschwiendet und somit nie verarbeitet wird.
Da hast du Recht. Man muss es auch verwenden, wenn man sicherstellen will, dass die Nachricht angekommen ist.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Bodenseematze

Registriert seit: 10. Jul 2023
68 Beiträge
 
#19

AW: Ursache für hängende Applikation herausfinden

  Alt 1. Feb 2024, 11:51
Mit Debugger starten, oder beim Hängen den Debugger anhängen
Würde ich gerne - aber:
Richtig debuggen kann ich schon lange (mehrere Jahre) nicht mehr - die Delphi IDE bleibt bei mir hängen, wenn ich versuche eine Applikation im Debugger zu starten - auch, wenn ich es über Remote-Debugging auf dem gleichen Rechner versuche (das funktioniert manchmal noch, aber meistens bleibt es auch hängen, wenn ich mich auf den laufenden Prozess setze).


Das hier...
Das sollte klar sein, aber zur Sicherheit frage ich einfach mal. Du greifst im Thread nicht auf irgendwelche VCL-Komponenten zu, oder?
Nicht, dass ich wüßte
But you are !
Zitat:
7736FF74 +0044 ntdll.dll RtlEnterCriticalSection
4002FE37 +0007 rtl70.bpl Classes ThreadList.LockList
01984929 +015D vcl70.bpl Controls TWinControl.PaintControls
See, there is no difference if you are accessing the thread itself from VCL or blocking to access something shared with a thread.
...und eine private Message von jaenicke hat mich auf die Spur der Ursache gebracht

Da es viele Aktionen abzuarbeiten gibt und das etwas länger dauert, verwende ich eine Mini-Form soz. als "Bitte Warten..."-Anzeige.
In dieser wird ein Anzeigetext gesetzt (ändert sich mit der aktuellen Aktion) und mit zu und abnehmenden "..." wird signalisiert, dass die Arbeit noch am Laufen ist.
Für dieses Zu- und Abnehmen habe ich eine eigene Klasse TTimerThread verwendet, die einen Thread basierten Timer zur Verfügung stellt bzw. stellen soll.
Eigentlich soll diese Klasse auch die Synchronisierung mit der VCL übernehmen - aber da scheint was nicht richtig zu sein.

Was da genau schief läuft, habe ich noch nicht herausgefunden - vielleicht findet jemand von Euch den Fehler im Code?

Das hier ist die Deklaration:
Delphi-Quellcode:
type
TTimerThread = class( TThread )
public
   constructor Create( bSuspend_ : Boolean = false ); virtual;
   destructor Destroy(); override;

   procedure Start();
   procedure Terminate();

   procedure SetTimerFunc( evTimerFunc_ : TNotifyEvent );


protected
   procedure Execute(); override;


private
   _evFlagCancel : TSimpleEvent;
   _evFlagEnabled : TSimpleEvent;
   _evTimerFunc : TNotifyEvent;
   _ui32IntervalInMs : UInt32;
   _bCallFuncOnMainThread : Boolean;

   procedure SetEnabled( bDoEnable_ : Boolean );
   function GetEnabled() : Boolean;

   procedure SetInterval( ui32IntervalInMs_ : UInt32 );

   procedure SwapToMainThread();


// Properties
public
   property Enabled : Boolean
                                    read GetEnabled
                                    write SetEnabled;

   property Interval : UInt32
                                    read _ui32IntervalInMs
                                    write SetInterval;

   // soll die OnTimer-Methode auf dem Main-Thread ausgeführt werden?
   property CallOnTimerOnMainThread : Boolean
                                    read _bCallFuncOnMainThread
                                    write _bCallFuncOnMainThread;

   // Anmerkung: OnTimer wird im Thread ausgeführt...
   property OnTimer : TNotifyEvent
                                    read _evTimerFunc
                                    write SetTimerFunc;
end; (* END_CLASS TTimerThread *)
und hier die Implementierung:
Delphi-Quellcode:
constructor TTimerThread.Create( bSuspend_ : Boolean = false );
begin
   inherited Create( true {* CreateSuspended *} );

   _bCallFuncOnMainThread := false;
   _ui32IntervalInMs := 1000;
   _evTimerFunc := nil;

   _evFlagEnabled := TSimpleEvent.Create();
   _evFlagEnabled.ResetEvent();
   _evFlagCancel := TSimpleEvent.Create();
   _evFlagCancel.ResetEvent();

   FreeOnTerminate := false;
   Priority := tpNormal;

   // lass den Thread loslaufen:
   if ( NOT bSuspend_ ) then begin
      Start();
   end;
end; (* END_CONSTRUCTOR TTimerThread.Create *)


destructor TTimerThread.Destroy();
begin
   Terminate();

   // synchronisieren:
   if ( GetCurrentThreadID = MainThreadID ) then begin
      WaitFor();
   end;

   FreeAndNil( _evFlagCancel );
   FreeAndNil( _evFlagEnabled );

   inherited Destroy();
end; (* END_DESTRUCTOR TTimerThread.Destroy *)


procedure TTimerThread.Terminate();
begin
   // Aufruf statische Methode TThread.Terminate:
   inherited Terminate();

   _evFlagEnabled.ResetEvent(); // Timer stoppen
   _evFlagCancel.SetEvent(); // Cancel-Flag setzen
end; (* END_PROC TTimerThread.Terminate *)


procedure TTimerThread.SetTimerFunc(
                                    evTimerFunc_ : TNotifyEvent );
begin
   _evTimerFunc := evTimerFunc_;
end; (* END_PROC TTimerThread.SetTimerFunc *)


procedure TTimerThread.SetEnabled(bDoEnable_ : Boolean );
begin
   if ( bDoEnable_ ) then begin
      _evFlagEnabled.SetEvent();
   end
   else begin
      _evFlagEnabled.ResetEvent();
   end;
end; (* END_PROC TTimerThread.SetEnabled *)


function TTimerThread.GetEnabled() : Boolean;
begin
   Result := false;
   if ( WaitForSingleObject(
                           _evFlagEnabled.Handle,
                           0) = WAIT_OBJECT_0 ) then begin
      Result := true;
   end;
end; (* END_FUNC TTimerThread.GetEnabled *)


procedure TTimerThread.SetInterval(
                                    ui32IntervalInMs_ : UInt32 );
begin
   _ui32IntervalInMs := ui32IntervalInMs_;
end; (* END_PROC TTimerThread.SetInterval *)


procedure TTimerThread.Start();
begin
   // startet einen bei Create nicht gestarteten Thread...
   Resume();
end; (* END_PROC TTimerThread.Start *)


procedure TTimerThread.Execute();
var
   arrWaitHandles : TWOHandleArray;
   i64WaitInterval : Int64;
   i64LastProcTime : Int64;
   i64Freq : Int64;
   i64Start : Int64;
   i64Stop : Int64;
   dwWaitResult : DWORD;
begin
   QueryPerformanceFrequency( i64Freq );

   arrWaitHandles[ 0 ] := _evFlagEnabled.Handle;
   arrWaitHandles[ 1 ] := _evFlagCancel.Handle;
   arrWaitHandles[ 2 ] := INVALID_HANDLE_VALUE;
   i64LastProcTime := 0;

   while ( (NOT Terminated) and (NOT Application.Terminated) ) do begin
      dwWaitResult := MsgWaitForMultipleObjects(
                                 2, {* nCount *}
                                 arrWaitHandles, {* var pHandles *}
                                 false, {* fWaitAll *}
                                 INFINITE, {* dwMilliseconds *}
                                 QS_ALLINPUT {* dwWakeMask *} );
      case dwWaitResult of
         WAIT_FAILED: begin // 0xFFFFFFFF
            // Fehler beim warten
            // --> da hören wir auf (Thread beenden)!
            Break;
         end;

         ( WAIT_OBJECT_0 + 1 ): begin // 0x00000001
            // Cancel-Event (_evFlagCancel)
            // --> Thread beenden
            Break;
         end;

         ( WAIT_OBJECT_0 + 0 ): begin // 0x00000000
            // Enable-Event (_evFlagEnabled)
            // --> Timer-Methode aufrufen
            if ( Assigned(_evTimerFunc) ) then begin
               i64WaitInterval := Int64( _ui32IntervalInMs ) - i64LastProcTime;
               if ( i64WaitInterval < 0 ) then begin
                  i64WaitInterval := 0;
               end;

               if ( WaitForSingleObject(
                                       _evFlagCancel.Handle,
                                       i64WaitInterval) <> WAIT_TIMEOUT ) then begin
                  // Cancel-Event _evFlagCancel
                  // --> Thread beenden
                  Break;
               end;

               if ( Enabled ) then begin
                  QueryPerformanceCounter( i64Start );
                  if ( Terminated or Application.Terminated ) then begin
                     Break;
                  end;
                  if ( Assigned(_evTimerFunc) ) then begin
                     if ( CallOnTimerOnMainThread ) then begin
                        // Methode indirekt auf dem Main-Thread aufrufen:
                        Synchronize( SwapToMainThread );
                     end
                     else begin
                        // Methode direkt aufrufen:
                        try
                           _evTimerFunc( Self );
                        except
                        end;
                     end;
                  end; // if ( Assigned(_evTimerFunc) ) then
                  QueryPerformanceCounter( i64Stop );
                  i64LastProcTime := ( 1000 * (i64Stop - i64Start) ) div i64Freq;
               end; // if ( Enabled ) then
            end; // if ( Assigned(_evTimerFunc) ) then
         end; // ( WAIT_OBJECT_0 + 1 ): begin

         else begin // ( WAIT_OBJECT_0 + 2 ) = 0x00000002
            // eine der Eingabe-Events (QS_ALLINPUT)
            // --> Nachrichten abarbeiten und wieder warten...
            Application.ProcessMessages();
         end;
      end; // case dwWaitResult of
   end; // while ( NOT Terminated ) do
end; (* END_PROC TTimerThread.Execute *)


procedure TTimerThread.SwapToMainThread();
begin
   if ( Assigned(_evTimerFunc) ) then begin
      try
         _evTimerFunc( Self );
      except
      end;
   end; // if ( Assigned(_evTimerFunc) ) then
end; (* END_PROC TTimerThread.SwapToMainThread *)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.572 Beiträge
 
Delphi 11 Alexandria
 
#20

AW: Ursache für hängende Applikation herausfinden

  Alt 1. Feb 2024, 12:20
Du rufst Application.ProcessMessages im Threadkontext auf und greifst damit ganz tief in die Messagebehandlung der VCL ein. Das kann nicht klappen.

In einer länger laufenden Methode, die im Hauptthread läuft, wird das verwendet, damit die GUI noch reagiert, indem dort die Paint-, Maus- und Tastaturmessages abgearbeitet werden. (Besser ist natürlich, das zu vermeiden.)

In einem Thread ist das nicht nötig (und auch nicht möglich). Wenn du warten möchtest, rufst du einfach Sleep auf. Da der Thread separat läuft, blockierst du damit auch nicht die GUI. Oder du wartest auf ein Event eine definierte Zeit.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 4     12 34      

 

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 01:37 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz