Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi [Thread] Thread im Deadlock abschießen (https://www.delphipraxis.net/122125-%5Bthread%5D-thread-im-deadlock-abschiessen.html)

s.h.a.r.k 9. Okt 2008 23:07


[Thread] Thread im Deadlock abschießen
 
guten abend alle miteinander,

ich hoffe, es gibt eine lösung für das folgende problem. und zwar geht es darum, dass wenn ein thread mal in einem deadlock endet, da dieser beispielsweise auf einen anderen wartet, dann würde ich diesen gerne "abschießen" wollen, d.h. ihn abbrechen und neu starten. ich habe mir vorgestellt, das dies "einfach" (*hust*, sonst würde ich hier ja nicht posten) ein .Free oder dergleichen erledigt, aber pustekuchen. habe mir eine anwendung geschrieben, mit der ich das testen kann, aber ich finde keine passende methode dafür, die das übernehmen kann.

ich hoffe jemand von euch hat mir hier eine lösung. mir ist klar, dass "es geht nicht" auch eine lösung ist, aber ich denke, da muss es doch eine möglichkeit geben. ich denke dabei allgemein an eine regenerative anwendung, die sich selbst überwacht und passend die internen "prozesse" neu startet.

mit freundlichen grüßen
armin

Dezipaitor 10. Okt 2008 00:01

Re: [Thread] Thread im Deadlock abschießen
 
Du solltest deine Wartestrategie auf andere Threads überdenken. Warte nicht unendlich sondern nur eine bestimmte Zeit. Oder du nutzt WaitForMultipleObjects und wartest auf den anderen Thread UND auf ein Stopsignal.
Und dann ganz am Ende kannst du immernoch TerminateThread nutzen.

alzaimar 10. Okt 2008 06:33

Re: [Thread] Thread im Deadlock abschießen
 
Wenn man das Objekt/Handle, auf das der Thread mit 'WaitForXXXObject' wartet, per 'CloseHandle' schließt, dann liefert die 'WaitXX' Routine den Wert 'WAIT_ABANDONED'.

Aber Dezipaitor hat Recht: Wenn Du in so eine Situation kommst, dann i.A. stimmt etwas nicht. Nur wenn Du zum Programmende alle Threads beenden willst, ist das imho legitim.

Du kannst auch den 'Terminated' Flag des Threads setzen und dann am Handle (z.B. der Semaphore) zupfen. Dann kommt das 'Wait' zurück und Du kannst als Erstes das 'Terminated' Flag prüfen.

mirage228 10. Okt 2008 07:21

Re: [Thread] Thread im Deadlock abschießen
 
Falls Du den Thread abschießen willst, geht das mit MSDN-Library durchsuchenTerminateThread.

Das sollte aber nur das letzte Mittel sein ...

Flocke 10. Okt 2008 16:56

Re: [Thread] Thread im Deadlock abschießen
 
Probier mal die folgenden Routinen, die Funktionsweise ist mir letztens eingefallen. Ich erzeuge einfach eine Exception in dem angegebenen Thread. Ist auch nicht 100%-ig sauber, aber immer noch besser als TerminateThread, besonders wenn die Dinge im Thread schön mit try..finally umklammert sind.

Delphi-Quellcode:
unit ThreadAbort;

interface

uses
  Windows, SysUtils, Classes;

{ These functions raise the given exception inside the given thread.
  The underscore variant simply returns False/True to indicate the success or
  failure of the action, while the other two raise an EOSError on that.
}
function _RaiseInThread(Which: THandle; E: Exception): Boolean;
procedure RaiseInThread(Which: THandle; E: Exception); overload;
procedure RaiseInThread(Which: TThread; E: Exception); overload;

{ These functions raise an EThreadAbort exception inside the given thread.
}
type
  EThreadAbort = class(Exception);

procedure AbortThread(Which: THandle; const Message: string = ''); overload;
procedure AbortThread(Which: TThread; const Message: string = ''); overload;

implementation

{ Raise an exception in the given thread.
}
function _RaiseInThread(Which: THandle; E: Exception): Boolean;
var
  Context: TContext;

  procedure Push(c: DWORD);
  begin
    Dec(Context.Esp, SizeOf(DWORD));
    PCardinal(Context.Esp)^ := c;
  end;

begin
  if Which = GetCurrentThread then
    raise E;

  Result := False;
  if SuspendThread(Which) = DWORD(-1) then
    Exit;
  try
    Context.ContextFlags := CONTEXT_CONTROL or CONTEXT_INTEGER;
    if not GetThreadContext(Which, Context) then
      Exit;

    { The following lines are copied from System.pas / _RaiseExcept,
      which (sadly) cannot be called directly. It uses the same calling
      convention since Delphi 3 (Delphi 2 uses a different signature).
    }
    Push(Context.Esp);
    Push(Context.Ebp);
    Push(Context.Edi);
    Push(Context.Esi);
    Push(Context.Ebx);
    Push(DWORD(E));                      { pass class argument        }
    Push(Context.Eip);                   { pass address argument      }

    Push(Context.Esp);                   { pass pointer to arguments  }
    Push(7);                             { there are seven arguments  }
    Push(1);           { cNonContinuable: we can't continue execution }
    Push($0EEDFADE);   { cDelphiException: our magic exception code   }
    Push(Context.Eip);                   { pass the return address    }

    {$IFDEF CONDITIONALEXPRESSIONS} // Delphi 6+
    Context.Eip := DWORD(RaiseExceptionProc);
    {$ELSE}
    Context.Eip := DWORD(@RaiseException);
    {$ENDIF}

    if SetThreadContext(Which, Context) then
      Result := True;
  finally
    if ResumeThread(Which) = DWORD(-1) then
      Result := False;
  end;
end;

procedure RaiseInThread(Which: THandle; E: Exception);
begin
  if not _RaiseInThread(Which, E) then
    RaiseLastOSError;
end;

procedure RaiseInThread(Which: TThread; E: Exception);
begin
  RaiseInThread(Which.Handle, E);
end;

procedure AbortThread(Which: THandle; const Message: string);
begin
  RaiseInThread(Which, EThreadAbort.Create(Message));
end;

procedure AbortThread(Which: TThread; const Message: string);
begin
  AbortThread(Which.Handle, Message);
end;

end.
Gib kurz Bescheid wenn was fehlt, ich habe den Code aus einer größeren Unit herauskopiert.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:07 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