Topaz Filer: if you use e-mail for business, we can save you money and decrease your risk.
BUG: Abort a Suspended Thread causes that thread hang
Messages   Related Types
This message was discovered on microsoft.public.dotnet.framework.clr.


Ming Chen [MVP]
GOOD ANSWER
Hi,
When I try Aborting a Suspended thread in .NET, there is an exception
thrown:
System.Threading.ThreadStateException: Thread is suspended; attempting to
abort.
at System.Threading.Thread.AbortInternal()
This is still fine, though it's already incosistent with .NET
Document(MSDN: "If Abort is called on a thread that has been suspended, the
thread is resumed and then aborted. "). The problem is after this exception,
that thread is hang. It won't response to any function call include Resume,
Suspend, Abort etc. And this hanging thread prevents the whole application
from terminating normally.
Here is a small test program which reproduces this problem (.NET Framework
with Service Pack 2):

using System;
using System.Threading;

public class AAA {
public static void Go() {
int i = 0;
try {
while(true) {
++ i;
Thread.Sleep(500);
Console.WriteLine("hello, " + i + " " + Thread.CurrentThread.ThreadState
+ ", " +
Thread.CurrentThread.IsAlive);
}
} catch(Exception e) {
Console.WriteLine("Thread Exception: " + e);
}
}

public static void Main() {
Thread t = new Thread(new ThreadStart(Go));
Thread.CurrentThread.Name = "Main Thread";
t.Name = "Hang Thread";
try {
t.Start();
Thread.Sleep(3000);
Console.WriteLine("Suspending... " + t.ThreadState + " " + t.IsAlive);
t.Suspend();
Thread.Sleep(1000);
Console.WriteLine("Aborting... " + t.ThreadState + " " + t.IsAlive);
t.Abort(); //Exception thrown here and the thread is lost.
} catch(Exception e) {
Console.WriteLine(e);
Console.WriteLine("Exceptioning... " + t.ThreadState + " " + t.IsAlive);
}
Console.WriteLine("Resuming... " + t.ThreadState + " " + t.IsAlive);
t.Resume(); //Called successfully but the thread will never
executing or terminate
}
}

Best Regards
Ming Chen

Reply to this message...
Vote that this is a GOOD answer... (31 votes from other users already)
 
 
    
Ming Chen [MVP]
GOOD ANSWER
A good thing about this bug is it could be reproduced with Rotor, which
allows me to really do some debug. ;)
In sscli\clr\src\vm\Threads.cpp, I fount following comments:

// What if someone else has this thread suspended already? It'll
depend where the
// thread got suspended.
//
// User Suspend:
// We'll just set the abort bit and hope for the best on the
resume.
//
// GC Suspend:
// If it's suspended in jitted code, we'll hijack the IP.
// If it's suspended but not in jitted code, we'll get suspended
for GC, the GC
// will complete, and then we'll abort the target thread.
And
// If the thread is user suspended (SyncSuspended) -- we're out of
luck. Set the bit and
// hope for the best on resume.

My understanding on those comments is for a suspended thread, Abort only
sets the abort flag and leave the real job to Thread.Resume. And for some
reasons, Abort would throw an exception after set that bit:

// ****** code from Rotor, threads.cpp line 4084 *********
if (m_State & TS_SyncSuspended) {
ThreadStore::TrapReturningThreads(FALSE);
ThreadStore::UnlockThreadStore();
COMPlusThrow(kThreadStateException,
IDS_EE_THREAD_ABORT_WHILE_SUSPEND);
_ASSERTE(0); // NOT REACHED
}

In each thread operation (Resume, Suspend and Abort), CLR will first call
API SuspendThread to suspend the physical thread to prevent it from moving
(Thread.Suspend and Thread.Resume don't directly hook up with API
SuspendThread and ResumeThread, thread class uses some events internally to
accomplish such jobs instead of calling API). Then does the real operation.
And before leaving those operation functions, CLR should call ResumeThread
to resume the physical thread.

// ****** code from Rotor, threads.cpp line 4031 *********
// Win32 suspend the thread, so it isn't moving under us.
#ifdef _DEBUG
DWORD oldSuspendCount = (DWORD)
#endif
::SuspendThread(hThread); // returns -1 on failure.

The Bad thing is, For Thread.Abort on a Suspended thread, that exception is
thrown and control leaves that function without Resume the underling
physical thread. So that thread is physically blocked at API level, any
further .NET function calls (include Thread.Resume) won't resume it because
they only perform event operations (SetEvent(m_SuspendEvent)). That thread
is completely lost from .NET world.

Here is my fixes for Rotor:
// ****** code from Rotor, threads.cpp line 4084 with fixes
*********
if (m_State & TS_SyncSuspended) {
// ThreadStore::TrapReturningThreads(FALSE); //mchen:
comment this line out
::ResumeThread(hThread); //mchen: Resume
the physical thread
ThreadStore::UnlockThreadStore();
COMPlusThrow(kThreadStateException,
IDS_EE_THREAD_ABORT_WHILE_SUSPEND);
_ASSERTE(0); // NOT REACHED
}

After these changes, the previous example passed and the thread is really
aborted upon Resume function call.

Hope this helps.
Ming Chen

"Ming Chen [MVP]" <Click here to reveal e-mail address> wrote in message
news:uTgO286SCHA.1632@tkmsftngp11...
[Original message clipped]

Reply to this message...
Vote that this is a GOOD answer... (27 votes from other users already)
 
 
 
System.Console
System.Threading.Thread
System.Threading.ThreadStart
System.Threading.ThreadStateException




Ad
BootFX
Reliable and powerful .NET application framework.
Recession Busting Bespoke Software
Get through the recession by investing in bespoke software to decrease costs and create commercial opportunities.
Other DN247 Network Sites
.NET 247
SQL Server Wins
Old Skool Developer
 
Copyright © AMX Software Ltd 2008-2009. Portions copyright © Matthew Baxter-Reynolds 2001-2009. All rights reserved.
Contact Us - Terms of Use - Privacy Policy - .NET 247 is a member of the DN247 Network - 4.0.30129.1734