Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here's a sample piece of code that raises an exception into an other thread. It uses <code>SuspendThread</code> to stop the thread, <code>GetThreadContext</code> to read the thread's registers, alters <code>EIP</code> (the instruction pointer), uses <code>SetThreadContext</code> and then <code>ResumeThread</code> to restart the thread. It works!</p> <h2>UKilThread unit</h2> <p>Nicely packaged for reuse unit that provides the <code>AbortThread()</code> routine:</p> <pre><code>unit UKillThread; interface uses Classes, Windows, SysUtils; procedure AbortThread(const Th: TThread); implementation // Exception to be raized on thread abort. type EThreadAbort = class(EAbort); // Procedure to raize the exception. Needs to be a simple, parameterless procedure // to simplify pointing the thread to this routine. procedure RaizeThreadAbort; begin raise EThreadAbort.Create('Thread was aborted using AbortThread()'); end; procedure AbortThread(const Th: TThread); const AlignAt = SizeOf(DWORD); // Undocumented; Apparently the memory used for _CONTEXT needs to be aligned on DWORD boundary var Block:array[0..SizeOf(_CONTEXT)+512] of Byte; // The _CONTEXT structure is probably larger then what Delphi thinks it should be. Unless I provide enough padding space, GetThreadContext fails ThContext: PContext; begin SuspendThread(Th.Handle); ZeroMemory(@Block, SizeOf(Block)); ThContext := PContext(((Integer(@Block) + AlignAt - 1) div AlignAt) * AlignAt); ThContext.ContextFlags := CONTEXT_FULL; if not GetThreadContext(Th.Handle, ThContext^) then RaiseLastOSError; ThContext.Eip := Cardinal(@RaizeThreadAbort); // Change EIP so we can redirect the thread to our error-raizing routine SetThreadContext(Th.Handle, ThContext^); ResumeThread(Th.Handle); end; end. </code></pre> <h2>Demo project</h2> <p>Here's how to use <code>AbortThread</code>:</p> <pre><code>program Project23; {$APPTYPE CONSOLE} uses SysUtils, Classes, Windows, UKillThread; var Th: TThread; type TTestThread = class(TThread) public procedure Execute;override; end; { TTestTrehad } procedure TTestThread.Execute; var N: Integer; begin try N := 1; while not Terminated do begin WriteLn(N); Inc(N); Sleep(1000); end; except on E:Exception do WriteLn(E.ClassName + ' / ' + E.Message); end; end; begin Th := TTestThread.Create(False); WriteLn('Press ENTER to raize exception in Thread'); ReadLn; AbortThread(Th); WriteLn('Press ENTER to exit'); ReadLn; end. </code></pre> <h2>Disclaimer</h2> <p>Please make sure you understand what this code does before you actually use it. This is by no means a replacement for proper <code>Terminate - Terminated</code> logic (that is, cooperative thread shut-down), but it's a better alternative to <code>TerminateThread()</code>. This has been modeled after the <a href="http://msdn.microsoft.com/en-us/library/ty8d3wta.aspx" rel="nofollow">.NET Thread.Abort()</a> method. I have no idea how the actual .NET method was implemented but none the less read up on that because the potential problems of using this code are similar:</p> <ul> <li>The method doesn't actually terminate the thread, it raises an <code>EAbort</code> -derived exception in the context of the thread. The thread's code might catch the exception. That's very unlikely because <code>EAbort</code> exceptions are not supposed to be handled.</li> <li>The method might stop the thread <em>at any time</em>. It might stop the thread while it's handling a <code>finally</code> section or while setting up a new exception frame. Even if your thread uses proper <code>try-finally</code> blocks, it might cause memory or resource leaks if the exception is raised after a resource has been allocated but before the resource has been assigned to a variable.</li> <li>The code might cause deadlocks if the thread is interrupted immediately after <code>EnterCriticalSection</code> and just before the <code>try-finally</code> that normally follows. The <a href="http://msdn.microsoft.com/en-us/library/ms682608%28v=vs.85%29.aspx" rel="nofollow">MSDN page for EnterCriticalSection</a> mentions: <code>"If a thread terminates while it has ownership of a critical section, the state of the critical section is undefined."</code>. This came as a surprise to me, I'd intuitively expect the critical section to be "released" when the owning thread terminates, but apparently that's not so.</li> </ul>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload