AW: Ursache für hängende Applikation herausfinden
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. |
AW: Ursache für hängende Applikation herausfinden
Zitat:
Zitat:
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... Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
|
AW: Ursache für hängende Applikation herausfinden
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. |
AW: Ursache für hängende Applikation herausfinden
Hi,
Zitat:
Zitat:
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. |
AW: Ursache für hängende Applikation herausfinden
Also es gibt das manchmal das Systemaufrufe einfach nicht zurrückkehren...
Hatte das mal mit diesem hier
Delphi-Quellcode:
Der StandardDrucker wurde in der Registry geändert und durch diesen REFRESH wird die Änderung wirksam...
SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE,0, Longint(@Device));//Registryänderung soll vom System gelesen werden.
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. |
AW: Ursache für hängende Applikation herausfinden
Zitat:
|
AW: Ursache für hängende Applikation herausfinden
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) |
AW: Ursache für hängende Applikation herausfinden
Zitat:
|
AW: Ursache für hängende Applikation herausfinden
Zitat:
Zitat:
Das hier... Zitat:
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:
und hier die Implementierung:
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 *)
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 *) |
AW: Ursache für hängende Applikation herausfinden
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. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:03 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