Search:
Namespaces
Discussions
.NET v1.1
Feedback
BUG: Abort a Suspended Thread causes that thread hang
Messages
Related Types
This message was discovered on
microsoft.public.dotnet.framework.clr
.
Post a new message to this list...
Ming Chen [MVP]
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...
Ming Chen [MVP]
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...
System.Console
System.Threading.Thread
System.Threading.ThreadStart
System.Threading.ThreadStateException
Ad
MBR BootFX
Best-of-breed application framework for .NET projects, developed by Matthew Baxter-Reynolds and MBR IT
Copyright © Matthew Baxter-Reynolds 2001-2008. '.NET 247 Software Development Services' is a trading style of MBR IT Solutions Ltd.
Contact Us
-
Terms of Use
-
Privacy Policy
-
www.dotnet247.com