Calling Win32 TerminateThread() via unmanaged code

B

Bryan

I have a multi-threaded C# console application that uses WMI
(System.Management namespace) to make RPC calls to several servers (600+ )
and returns ScheduledJobs. The section of my code that performs the query
is contained in a delegate function that I execute via a second thread. On 1
or 2 of the 600+ servers the query hangs. I've tried to use Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Based on other post I've read this is a common occurrence and the only way
to kill this thread is to use TerminateThread() located in the Kernel32.dll.
I'm not really sure how to call this unmanaged code. Also TerminateThread()
requires the thread's handle and I'm not sure how to obtain this in .NET.
I've made a "best guess" at the code but it doesn't work. See sample below.
Can anyone give me a code sample of how this can be done? This is my first
multi-threaded application and I'm pretty much a newbie to unmanaged code.

// This class allows me to pass a server name to the function
// and still call it as a delegate.

public class Parcer
{
public int ThreadID;
private string Server;
public DataSet ds;
public Parcer(string Server)
{
this.Server = Server;
}

public void ParceJobs()
{
ThreadID = AppDomain.GetCurrentThreadId();
IntelJobReader JobReader = new IntelJobReader(); //Instanciate the
JobReader object. This is a class I wrote that make the WMI calls and
returns a DataSet.
DataSet JobSchedules = ( DataSet ) ( JobReader.GetSvrJobs(Server) );
this.ds = JobSchedules;
}
}

// This is my best guess at the unmanaged code. It runs without error but
does not terminate the thread.

public class Win32
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern int TerminateThread(int hThread);
}

// Excerpt from my Conseole App's Main code:

Parcer SchJobs = new Parcer(Server);
Thread JobTimeout = new Thread(new ThreadStart(SchJobs.ParceJobs));
JobTimeout.Start();
JobTimeout.Join(10000);
if (!JobTimeout.Join(10000))
{
JobTimeout.Abort(); // This will not terminate the thread
Win32.TerminateThread(AppDomain.GetCurrentThreadId());
Console.WriteLine("The thread timed out no change will be made to the
DB");
}

Thanks,
Bryan
 
D

Dmitriy Lapshin [C# / .NET MVP]

On 1 or 2 of the 600+ servers the query hangs. I've tried to use
Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Ensure the sequence was Thread.Abort() first and then Thread.Join(), not the
other way around.
Calling Thread.Join() first will result in a deadlock you are probably
experiencing.

As for the TerminateThread, this API function has two parameters (the second
one is also int), but I am not sure how one can obtain the handle of the
thread. You might need to resort to the GetCurrentThread() API to do that.

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://x-unity.miik.com.ua/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

Bryan said:
I have a multi-threaded C# console application that uses WMI
(System.Management namespace) to make RPC calls to several servers (600+ )
and returns ScheduledJobs. The section of my code that performs the query
is contained in a delegate function that I execute via a second thread. On 1
or 2 of the 600+ servers the query hangs. I've tried to use Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Based on other post I've read this is a common occurrence and the only way
to kill this thread is to use TerminateThread() located in the Kernel32.dll.
I'm not really sure how to call this unmanaged code. Also TerminateThread()
requires the thread's handle and I'm not sure how to obtain this in .NET.
I've made a "best guess" at the code but it doesn't work. See sample below.
Can anyone give me a code sample of how this can be done? This is my first
multi-threaded application and I'm pretty much a newbie to unmanaged code.

// This class allows me to pass a server name to the function
// and still call it as a delegate.

public class Parcer
{
public int ThreadID;
private string Server;
public DataSet ds;
public Parcer(string Server)
{
this.Server = Server;
}

public void ParceJobs()
{
ThreadID = AppDomain.GetCurrentThreadId();
IntelJobReader JobReader = new IntelJobReader(); //Instanciate the
JobReader object. This is a class I wrote that make the WMI calls and
returns a DataSet.
DataSet JobSchedules = ( DataSet ) (
JobReader.GetSvrJobs(Server) );
this.ds = JobSchedules;
}
}

// This is my best guess at the unmanaged code. It runs without error but
does not terminate the thread.

public class Win32
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern int TerminateThread(int hThread);
}

// Excerpt from my Conseole App's Main code:

Parcer SchJobs = new Parcer(Server);
Thread JobTimeout = new Thread(new ThreadStart(SchJobs.ParceJobs));
JobTimeout.Start();
JobTimeout.Join(10000);
if (!JobTimeout.Join(10000))
{
JobTimeout.Abort(); // This will not terminate the thread
Win32.TerminateThread(AppDomain.GetCurrentThreadId());
Console.WriteLine("The thread timed out no change will be made to the
DB");
}

Thanks,
Bryan
 
W

Willy Denoyette [MVP]

You should never call ThreadTerminate, it will corrupt the process, or
worse, if called while it holds a lock on the OS heap, all other threads in
the system trying to allocate/free memory blocks from the same heap will
block forever.
Calling Thread.Abort() from another thread (asynch.) is also problematic:
1. When the thread is blocked in unmanaged code, Abort will suspend until a
return from unmanaged code is done and a safe point for GC is reached.
2. Asynchronous Thread.Abort's should be deferred when executing a finally
clause, this is not done in v1.1, possibly resulting in resource leaks and
corrupted state.

I would suggest you revise the portion of your "Management/WMI" code, IMO
the solution should be found in there as it's the source of the problem
(blocking thread).
Another point to check is whether your code runs on a MTA thread (see
MTA/STAThread attribute on Main), too many people get bitten by this.

Willy.


Bryan said:
I have a multi-threaded C# console application that uses WMI
(System.Management namespace) to make RPC calls to several servers (600+ )
and returns ScheduledJobs. The section of my code that performs the query
is contained in a delegate function that I execute via a second thread. On 1
or 2 of the 600+ servers the query hangs. I've tried to use Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Based on other post I've read this is a common occurrence and the only way
to kill this thread is to use TerminateThread() located in the Kernel32.dll.
I'm not really sure how to call this unmanaged code. Also TerminateThread()
requires the thread's handle and I'm not sure how to obtain this in .NET.
I've made a "best guess" at the code but it doesn't work. See sample below.
Can anyone give me a code sample of how this can be done? This is my first
multi-threaded application and I'm pretty much a newbie to unmanaged code.
// This class allows me to pass a server name to the function
// and still call it as a delegate.

public class Parcer
{
public int ThreadID;
private string Server;
public DataSet ds;
public Parcer(string Server)
{
this.Server = Server;
}

public void ParceJobs()
{
ThreadID = AppDomain.GetCurrentThreadId();
IntelJobReader JobReader = new IntelJobReader(); //Instanciate the
JobReader object. This is a class I wrote that make the WMI calls and
returns a DataSet.
DataSet JobSchedules = ( DataSet ) (
JobReader.GetSvrJobs(Server) );
this.ds = JobSchedules;
}
}

// This is my best guess at the unmanaged code. It runs without error but
does not terminate the thread.

public class Win32
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern int TerminateThread(int hThread);
}

// Excerpt from my Conseole App's Main code:

Parcer SchJobs = new Parcer(Server);
Thread JobTimeout = new Thread(new ThreadStart(SchJobs.ParceJobs));
JobTimeout.Start();
JobTimeout.Join(10000);
if (!JobTimeout.Join(10000))
{
JobTimeout.Abort(); // This will not terminate the thread
Win32.TerminateThread(AppDomain.GetCurrentThreadId());
Console.WriteLine("The thread timed out no change will be made to the
DB");
}

Thanks,
Bryan
 
D

Dmitriy Lapshin [C# / .NET MVP]

Hello Willy,
Another point to check is whether your code runs on a MTA thread (see
MTA/STAThread attribute on Main), too many people get bitten by this.

Could you please elaborate on this? I know what is STA and what is MTA, but
how does it related to aborting a worker thread?

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://x-unity.miik.com.ua/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

Willy Denoyette said:
You should never call ThreadTerminate, it will corrupt the process, or
worse, if called while it holds a lock on the OS heap, all other threads in
the system trying to allocate/free memory blocks from the same heap will
block forever.
Calling Thread.Abort() from another thread (asynch.) is also problematic:
1. When the thread is blocked in unmanaged code, Abort will suspend until a
return from unmanaged code is done and a safe point for GC is reached.
2. Asynchronous Thread.Abort's should be deferred when executing a finally
clause, this is not done in v1.1, possibly resulting in resource leaks and
corrupted state.

I would suggest you revise the portion of your "Management/WMI" code, IMO
the solution should be found in there as it's the source of the problem
(blocking thread).
Another point to check is whether your code runs on a MTA thread (see
MTA/STAThread attribute on Main), too many people get bitten by this.

Willy.


Bryan said:
I have a multi-threaded C# console application that uses WMI
(System.Management namespace) to make RPC calls to several servers (600+ )
and returns ScheduledJobs. The section of my code that performs the query
is contained in a delegate function that I execute via a second thread.
On
1
or 2 of the 600+ servers the query hangs. I've tried to use Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Based on other post I've read this is a common occurrence and the only way
to kill this thread is to use TerminateThread() located in the Kernel32.dll.
I'm not really sure how to call this unmanaged code. Also TerminateThread()
requires the thread's handle and I'm not sure how to obtain this in ..NET.
I've made a "best guess" at the code but it doesn't work. See sample below.
Can anyone give me a code sample of how this can be done? This is my first
multi-threaded application and I'm pretty much a newbie to unmanaged
code.
// This class allows me to pass a server name to the function
// and still call it as a delegate.

public class Parcer
{
public int ThreadID;
private string Server;
public DataSet ds;
public Parcer(string Server)
{
this.Server = Server;
}

public void ParceJobs()
{
ThreadID = AppDomain.GetCurrentThreadId();
IntelJobReader JobReader = new IntelJobReader(); //Instanciate the
JobReader object. This is a class I wrote that make the WMI calls and
returns a DataSet.
DataSet JobSchedules = ( DataSet ) (
JobReader.GetSvrJobs(Server) );
this.ds = JobSchedules;
}
}

// This is my best guess at the unmanaged code. It runs without error but
does not terminate the thread.

public class Win32
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern int TerminateThread(int hThread);
}

// Excerpt from my Conseole App's Main code:

Parcer SchJobs = new Parcer(Server);
Thread JobTimeout = new Thread(new ThreadStart(SchJobs.ParceJobs));
JobTimeout.Start();
JobTimeout.Join(10000);
if (!JobTimeout.Join(10000))
{
JobTimeout.Abort(); // This will not terminate the thread
Win32.TerminateThread(AppDomain.GetCurrentThreadId());
Console.WriteLine("The thread timed out no change will be made to the
DB");
}

Thanks,
Bryan
 
B

Bryan

Thanks for the reply. I do call the Abort before the Join however the
thread still hangs. Any idea how I can create the pointer to the thread and
call TerminateThread()?



Dmitriy Lapshin said:
On 1 or 2 of the 600+ servers the query hangs. I've tried to use Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Ensure the sequence was Thread.Abort() first and then Thread.Join(), not the
other way around.
Calling Thread.Join() first will result in a deadlock you are probably
experiencing.

As for the TerminateThread, this API function has two parameters (the second
one is also int), but I am not sure how one can obtain the handle of the
thread. You might need to resort to the GetCurrentThread() API to do that.

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://x-unity.miik.com.ua/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

Bryan said:
I have a multi-threaded C# console application that uses WMI
(System.Management namespace) to make RPC calls to several servers (600+ )
and returns ScheduledJobs. The section of my code that performs the query
is contained in a delegate function that I execute via a second thread.
On
1
or 2 of the 600+ servers the query hangs. I've tried to use Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Based on other post I've read this is a common occurrence and the only way
to kill this thread is to use TerminateThread() located in the Kernel32.dll.
I'm not really sure how to call this unmanaged code. Also TerminateThread()
requires the thread's handle and I'm not sure how to obtain this in ..NET.
I've made a "best guess" at the code but it doesn't work. See sample below.
Can anyone give me a code sample of how this can be done? This is my first
multi-threaded application and I'm pretty much a newbie to unmanaged code.

// This class allows me to pass a server name to the function
// and still call it as a delegate.

public class Parcer
{
public int ThreadID;
private string Server;
public DataSet ds;
public Parcer(string Server)
{
this.Server = Server;
}

public void ParceJobs()
{
ThreadID = AppDomain.GetCurrentThreadId();
IntelJobReader JobReader = new IntelJobReader(); //Instanciate the
JobReader object. This is a class I wrote that make the WMI calls and
returns a DataSet.
DataSet JobSchedules = ( DataSet ) (
JobReader.GetSvrJobs(Server) );
this.ds = JobSchedules;
}
}

// This is my best guess at the unmanaged code. It runs without error but
does not terminate the thread.

public class Win32
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern int TerminateThread(int hThread);
}

// Excerpt from my Conseole App's Main code:

Parcer SchJobs = new Parcer(Server);
Thread JobTimeout = new Thread(new ThreadStart(SchJobs.ParceJobs));
JobTimeout.Start();
JobTimeout.Join(10000);
if (!JobTimeout.Join(10000))
{
JobTimeout.Abort(); // This will not terminate the thread
Win32.TerminateThread(AppDomain.GetCurrentThreadId());
Console.WriteLine("The thread timed out no change will be made to the
DB");
}

Thanks,
Bryan
 
D

Dave

Calling TerminateThread will not do what you want it to do. Even if you were
able to kill the underlying OS thread the CLR will not "know" that you did
this and so the CLR's managed thread would still be waiting (forever) for
the unmanaged thread to return back to the managed world.

In addition, killing an OS thread has LOTS of side-effects; its stack never
gets deallocated, mutexes and critical sections it owns never get released
etc. Unless your own code controls the thread (setting up its own restricted
environment so that it cannot allocate a system resource that requires
cleanup) it is very dangerous to do this. Even in Win32 land the docs warn
you to only do this as an asbolute last resort. Based on your sample code
there's nothing there that appears to be of such a mission critical nature
that this is required.

IMO this is one of the areas in .NET that is not completely baked. It's done
well enough that you want to do use it but there really isn't enough control
over the execution model that you can reliably control other threads. This
is especially noticable in the case you've run into, that of P/Invoking to
an unmanaged API that hangs.

An option you can take all the code that p/invokes and may hang and remote
it from another appdomain. When you want to terminate all those threads
unload the appdomain. I've noticed that the runtime does a better job of
unwinding all those threads when it unloads an appdomain then when you
simply try to abort the thread. Make sure you mark all those threads as
background.


Bryan said:
Thanks for the reply. I do call the Abort before the Join however the
thread still hangs. Any idea how I can create the pointer to the thread and
call TerminateThread()?



Dmitriy Lapshin said:
On 1 or 2 of the 600+ servers the query hangs. I've tried to use Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Ensure the sequence was Thread.Abort() first and then Thread.Join(), not the
other way around.
Calling Thread.Join() first will result in a deadlock you are probably
experiencing.

As for the TerminateThread, this API function has two parameters (the second
one is also int), but I am not sure how one can obtain the handle of the
thread. You might need to resort to the GetCurrentThread() API to do that.

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://x-unity.miik.com.ua/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

Bryan said:
I have a multi-threaded C# console application that uses WMI
(System.Management namespace) to make RPC calls to several servers (600+ )
and returns ScheduledJobs. The section of my code that performs the query
is contained in a delegate function that I execute via a second
thread.
On
1
or 2 of the 600+ servers the query hangs. I've tried to use Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Based on other post I've read this is a common occurrence and the only way
to kill this thread is to use TerminateThread() located in the Kernel32.dll.
I'm not really sure how to call this unmanaged code. Also TerminateThread()
requires the thread's handle and I'm not sure how to obtain this in .NET.
I've made a "best guess" at the code but it doesn't work. See sample below.
Can anyone give me a code sample of how this can be done? This is my first
multi-threaded application and I'm pretty much a newbie to unmanaged code.

// This class allows me to pass a server name to the function
// and still call it as a delegate.

public class Parcer
{
public int ThreadID;
private string Server;
public DataSet ds;
public Parcer(string Server)
{
this.Server = Server;
}

public void ParceJobs()
{
ThreadID = AppDomain.GetCurrentThreadId();
IntelJobReader JobReader = new IntelJobReader(); //Instanciate the
JobReader object. This is a class I wrote that make the WMI calls and
returns a DataSet.
DataSet JobSchedules = ( DataSet ) (
JobReader.GetSvrJobs(Server) );
this.ds = JobSchedules;
}
}

// This is my best guess at the unmanaged code. It runs without error but
does not terminate the thread.

public class Win32
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern int TerminateThread(int hThread);
}

// Excerpt from my Conseole App's Main code:

Parcer SchJobs = new Parcer(Server);
Thread JobTimeout = new Thread(new ThreadStart(SchJobs.ParceJobs));
JobTimeout.Start();
JobTimeout.Join(10000);
if (!JobTimeout.Join(10000))
{
JobTimeout.Abort(); // This will not terminate the thread
Win32.TerminateThread(AppDomain.GetCurrentThreadId());
Console.WriteLine("The thread timed out no change will be made to the
DB");
}

Thanks,
Bryan
 
W

Willy Denoyette [MVP]

It doesn't relate, my point was to forget about aborting a thread
asynchronously.
IMO, OP should take a look at the WMI related code, maybe WMI calls could be
done asynchronously i.s.o synchronously (blocking), that way you don't have
to try to abort a blocked thread (something that doesn't work after all,
unless by calling ThreadTerminate).

Willy.


Dmitriy Lapshin said:
Hello Willy,
Another point to check is whether your code runs on a MTA thread (see
MTA/STAThread attribute on Main), too many people get bitten by this.

Could you please elaborate on this? I know what is STA and what is MTA, but
how does it related to aborting a worker thread?

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://x-unity.miik.com.ua/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

Willy Denoyette said:
You should never call ThreadTerminate, it will corrupt the process, or
worse, if called while it holds a lock on the OS heap, all other threads in
the system trying to allocate/free memory blocks from the same heap will
block forever.
Calling Thread.Abort() from another thread (asynch.) is also problematic:
1. When the thread is blocked in unmanaged code, Abort will suspend
until
a
return from unmanaged code is done and a safe point for GC is reached.
2. Asynchronous Thread.Abort's should be deferred when executing a finally
clause, this is not done in v1.1, possibly resulting in resource leaks and
corrupted state.

I would suggest you revise the portion of your "Management/WMI" code, IMO
the solution should be found in there as it's the source of the problem
(blocking thread).
Another point to check is whether your code runs on a MTA thread (see
MTA/STAThread attribute on Main), too many people get bitten by this.

Willy.
thread.
On
1
or 2 of the 600+ servers the query hangs. I've tried to use Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Based on other post I've read this is a common occurrence and the only way
to kill this thread is to use TerminateThread() located in the Kernel32.dll.
I'm not really sure how to call this unmanaged code. Also TerminateThread()
requires the thread's handle and I'm not sure how to obtain this in .NET.
I've made a "best guess" at the code but it doesn't work. See sample below.
Can anyone give me a code sample of how this can be done? This is my first
multi-threaded application and I'm pretty much a newbie to unmanaged
code.
// This class allows me to pass a server name to the function
// and still call it as a delegate.

public class Parcer
{
public int ThreadID;
private string Server;
public DataSet ds;
public Parcer(string Server)
{
this.Server = Server;
}

public void ParceJobs()
{
ThreadID = AppDomain.GetCurrentThreadId();
IntelJobReader JobReader = new IntelJobReader(); //Instanciate the
JobReader object. This is a class I wrote that make the WMI calls and
returns a DataSet.
DataSet JobSchedules = ( DataSet ) (
JobReader.GetSvrJobs(Server) );
this.ds = JobSchedules;
}
}

// This is my best guess at the unmanaged code. It runs without error but
does not terminate the thread.

public class Win32
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern int TerminateThread(int hThread);
}

// Excerpt from my Conseole App's Main code:

Parcer SchJobs = new Parcer(Server);
Thread JobTimeout = new Thread(new ThreadStart(SchJobs.ParceJobs));
JobTimeout.Start();
JobTimeout.Join(10000);
if (!JobTimeout.Join(10000))
{
JobTimeout.Abort(); // This will not terminate the thread
Win32.TerminateThread(AppDomain.GetCurrentThreadId());
Console.WriteLine("The thread timed out no change will be made to the
DB");
}

Thanks,
Bryan
 
W

Willy Denoyette [MVP]

Agreed, TerminateThread is a no no in managed land (IMO this API should
never have been publicly exposed :)).
But OP doesn't call through P/Invoke, he's using the Management classes
which do sit on top of COM WMI, things get even more complicated as OP is
calling remote WMI services on 600+ remote PC's.
Remoting WMI services are implemented over SMB RPC's, not DCOM, only the
fact that some of the remote servers are unavailable or not responding, will
disturb the whole process if not carefully designed.
Another thing that complicates maters is the interfacing between .NET and
COM, which imposes threading requirements usually not know by the average
..NET developer (.NET replaces COM right?).

Willy.


Dave said:
Calling TerminateThread will not do what you want it to do. Even if you were
able to kill the underlying OS thread the CLR will not "know" that you did
this and so the CLR's managed thread would still be waiting (forever) for
the unmanaged thread to return back to the managed world.

In addition, killing an OS thread has LOTS of side-effects; its stack never
gets deallocated, mutexes and critical sections it owns never get released
etc. Unless your own code controls the thread (setting up its own restricted
environment so that it cannot allocate a system resource that requires
cleanup) it is very dangerous to do this. Even in Win32 land the docs warn
you to only do this as an asbolute last resort. Based on your sample code
there's nothing there that appears to be of such a mission critical nature
that this is required.

IMO this is one of the areas in .NET that is not completely baked. It's done
well enough that you want to do use it but there really isn't enough control
over the execution model that you can reliably control other threads. This
is especially noticable in the case you've run into, that of P/Invoking to
an unmanaged API that hangs.

An option you can take all the code that p/invokes and may hang and remote
it from another appdomain. When you want to terminate all those threads
unload the appdomain. I've noticed that the runtime does a better job of
unwinding all those threads when it unloads an appdomain then when you
simply try to abort the thread. Make sure you mark all those threads as
background.


Bryan said:
Thanks for the reply. I do call the Abort before the Join however the
thread still hangs. Any idea how I can create the pointer to the thread and
call TerminateThread()?



in message news:[email protected]...
On 1 or 2 of the 600+ servers the query hangs. I've tried to use
Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Ensure the sequence was Thread.Abort() first and then Thread.Join(),
not
the
other way around.
Calling Thread.Join() first will result in a deadlock you are probably
experiencing.

As for the TerminateThread, this API function has two parameters (the second
one is also int), but I am not sure how one can obtain the handle of the
thread. You might need to resort to the GetCurrentThread() API to do that.

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://x-unity.miik.com.ua/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

I have a multi-threaded C# console application that uses WMI
(System.Management namespace) to make RPC calls to several servers (600+ )
and returns ScheduledJobs. The section of my code that performs the query
is contained in a delegate function that I execute via a second
thread.
On
1
or 2 of the 600+ servers the query hangs. I've tried to use Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Based on other post I've read this is a common occurrence and the
only
way
to kill this thread is to use TerminateThread() located in the
Kernel32.dll.
I'm not really sure how to call this unmanaged code. Also
TerminateThread()
requires the thread's handle and I'm not sure how to obtain this in .NET.
I've made a "best guess" at the code but it doesn't work. See sample
below.
Can anyone give me a code sample of how this can be done? This is my
first
multi-threaded application and I'm pretty much a newbie to unmanaged code.

// This class allows me to pass a server name to the function
// and still call it as a delegate.

public class Parcer
{
public int ThreadID;
private string Server;
public DataSet ds;
public Parcer(string Server)
{
this.Server = Server;
}

public void ParceJobs()
{
ThreadID = AppDomain.GetCurrentThreadId();
IntelJobReader JobReader = new IntelJobReader();
//Instanciate
the
JobReader object. This is a class I wrote that make the WMI calls and
returns a DataSet.
DataSet JobSchedules = ( DataSet ) (
JobReader.GetSvrJobs(Server) );
this.ds = JobSchedules;
}
}

// This is my best guess at the unmanaged code. It runs without
error
but
does not terminate the thread.

public class Win32
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern int TerminateThread(int hThread);
}

// Excerpt from my Conseole App's Main code:

Parcer SchJobs = new Parcer(Server);
Thread JobTimeout = new Thread(new ThreadStart(SchJobs.ParceJobs));
JobTimeout.Start();
JobTimeout.Join(10000);
if (!JobTimeout.Join(10000))
{
JobTimeout.Abort(); // This will not terminate the thread
Win32.TerminateThread(AppDomain.GetCurrentThreadId());
Console.WriteLine("The thread timed out no change will be made
to
the
DB");
}

Thanks,
Bryan
 
B

Bryan

Thanks for your help guys what you are saying makes sense. Since the call
is unmanaged even if the thread is "terminated".NET won't know it. I've
seen this problem posted a few times on various news groups and have never
seen an actual Microsoft response. It seems to me that this is an issue
that really needs to be addressed.

I've never tried to initiate a separate AppDomain but I'm sure I can figure
it out. I'll do some research and give it a try. Will post a solution when
I have one.


Thanks again,
Bryan


Willy Denoyette said:
Agreed, TerminateThread is a no no in managed land (IMO this API should
never have been publicly exposed :)).
But OP doesn't call through P/Invoke, he's using the Management classes
which do sit on top of COM WMI, things get even more complicated as OP is
calling remote WMI services on 600+ remote PC's.
Remoting WMI services are implemented over SMB RPC's, not DCOM, only the
fact that some of the remote servers are unavailable or not responding, will
disturb the whole process if not carefully designed.
Another thing that complicates maters is the interfacing between .NET and
COM, which imposes threading requirements usually not know by the average
.NET developer (.NET replaces COM right?).

Willy.


Dave said:
Calling TerminateThread will not do what you want it to do. Even if you were
able to kill the underlying OS thread the CLR will not "know" that you did
this and so the CLR's managed thread would still be waiting (forever) for
the unmanaged thread to return back to the managed world.

In addition, killing an OS thread has LOTS of side-effects; its stack never
gets deallocated, mutexes and critical sections it owns never get released
etc. Unless your own code controls the thread (setting up its own restricted
environment so that it cannot allocate a system resource that requires
cleanup) it is very dangerous to do this. Even in Win32 land the docs warn
you to only do this as an asbolute last resort. Based on your sample code
there's nothing there that appears to be of such a mission critical nature
that this is required.

IMO this is one of the areas in .NET that is not completely baked. It's done
well enough that you want to do use it but there really isn't enough control
over the execution model that you can reliably control other threads. This
is especially noticable in the case you've run into, that of P/Invoking to
an unmanaged API that hangs.

An option you can take all the code that p/invokes and may hang and remote
it from another appdomain. When you want to terminate all those threads
unload the appdomain. I've noticed that the runtime does a better job of
unwinding all those threads when it unloads an appdomain then when you
simply try to abort the thread. Make sure you mark all those threads as
background.


Bryan said:
Thanks for the reply. I do call the Abort before the Join however the
thread still hangs. Any idea how I can create the pointer to the
thread
and
call TerminateThread()?



in message On 1 or 2 of the 600+ servers the query hangs. I've tried to use
Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Ensure the sequence was Thread.Abort() first and then Thread.Join(), not
the
other way around.
Calling Thread.Join() first will result in a deadlock you are probably
experiencing.

As for the TerminateThread, this API function has two parameters (the
second
one is also int), but I am not sure how one can obtain the handle of the
thread. You might need to resort to the GetCurrentThread() API to do that.

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://x-unity.miik.com.ua/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

I have a multi-threaded C# console application that uses WMI
(System.Management namespace) to make RPC calls to several servers
(600+ )
and returns ScheduledJobs. The section of my code that performs the
query
is contained in a delegate function that I execute via a second thread.
On
1
or 2 of the 600+ servers the query hangs. I've tried to use
Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Based on other post I've read this is a common occurrence and the only
way
to kill this thread is to use TerminateThread() located in the
Kernel32.dll.
I'm not really sure how to call this unmanaged code. Also
TerminateThread()
requires the thread's handle and I'm not sure how to obtain this in
.NET.
I've made a "best guess" at the code but it doesn't work. See sample
below.
Can anyone give me a code sample of how this can be done? This is my
first
multi-threaded application and I'm pretty much a newbie to unmanaged
code.

// This class allows me to pass a server name to the function
// and still call it as a delegate.

public class Parcer
{
public int ThreadID;
private string Server;
public DataSet ds;
public Parcer(string Server)
{
this.Server = Server;
}

public void ParceJobs()
{
ThreadID = AppDomain.GetCurrentThreadId();
IntelJobReader JobReader = new IntelJobReader(); //Instanciate
the
JobReader object. This is a class I wrote that make the WMI calls and
returns a DataSet.
DataSet JobSchedules = ( DataSet ) (
JobReader.GetSvrJobs(Server) );
this.ds = JobSchedules;
}
}

// This is my best guess at the unmanaged code. It runs without error
but
does not terminate the thread.

public class Win32
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern int TerminateThread(int hThread);
}

// Excerpt from my Conseole App's Main code:

Parcer SchJobs = new Parcer(Server);
Thread JobTimeout = new Thread(new ThreadStart(SchJobs.ParceJobs));
JobTimeout.Start();
JobTimeout.Join(10000);
if (!JobTimeout.Join(10000))
{
JobTimeout.Abort(); // This will not terminate the thread
Win32.TerminateThread(AppDomain.GetCurrentThreadId());
Console.WriteLine("The thread timed out no change will be made to
the
DB");
}

Thanks,
Bryan
 
D

Dave

Agreed, TerminateThread is a no no in managed land (IMO this API should
never have been publicly exposed :)).

Actually I disagree. It's usually abused and used incorrectly but for some
applications there is no substitute. We only used it as an absolute last
resort but it was necessary (and we did understand all the downsides to it).


IMO .NET wont be a suitable replacement for some Win32 apps until it has a
better story on a few key issues; aborting threads blocked in unmanaged
code, and uninterruptable finally blocks.
But OP doesn't call through P/Invoke, he's using the Management classes
which do sit on top of COM WMI, things get even more complicated as OP is

I must be acronym challenged this morning; what does OP stand for?
calling remote WMI services on 600+ remote PC's.
Remoting WMI services are implemented over SMB RPC's, not DCOM, only the>
fact that some of the remote servers are unavailable or not responding, will
disturb the whole process if not carefully designed.
Another thing that complicates maters is the interfacing between .NET and
COM, which imposes threading requirements usually not know by the average
.NET developer (.NET replaces COM right?).

I don't understand those issues that well - I skipped over most of the COM
era and went from Win32 to .NET. What sorts of threading related issues can
you point out that I (everyone) should be aware of?
 
D

Dmitriy Lapshin [C# / .NET MVP]

Willy,

I was asking this because I am facing a similar problem. There's a managed
thread that does some work and should be able to be terminated at any time
by the user clicking on a kind of "Stop" button (like in IE). The thread to
be stopped is expected to mainly execute managed code, but it is not
guaranteed it will never use P/Invoke (the main part of the thread's
activity is running a third-party code I can make no assumptions of). In
this scenario, I believe there is no other way to stop the thread than
calling TerminateThread - of course when Thread.Abort() and Thread.Join
timed out.

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://x-unity.miik.com.ua/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

Willy Denoyette said:
It doesn't relate, my point was to forget about aborting a thread
asynchronously.
IMO, OP should take a look at the WMI related code, maybe WMI calls could be
done asynchronously i.s.o synchronously (blocking), that way you don't have
to try to abort a blocked thread (something that doesn't work after all,
unless by calling ThreadTerminate).

Willy.


Dmitriy Lapshin said:
Hello Willy,
Another point to check is whether your code runs on a MTA thread (see
MTA/STAThread attribute on Main), too many people get bitten by this.

Could you please elaborate on this? I know what is STA and what is MTA, but
how does it related to aborting a worker thread?

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://x-unity.miik.com.ua/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

Willy Denoyette said:
You should never call ThreadTerminate, it will corrupt the process, or
worse, if called while it holds a lock on the OS heap, all other
threads
in
the system trying to allocate/free memory blocks from the same heap will
block forever.
Calling Thread.Abort() from another thread (asynch.) is also problematic:
1. When the thread is blocked in unmanaged code, Abort will suspend
until
a
return from unmanaged code is done and a safe point for GC is reached.
2. Asynchronous Thread.Abort's should be deferred when executing a finally
clause, this is not done in v1.1, possibly resulting in resource leaks and
corrupted state.

I would suggest you revise the portion of your "Management/WMI" code, IMO
the solution should be found in there as it's the source of the problem
(blocking thread).
Another point to check is whether your code runs on a MTA thread (see
MTA/STAThread attribute on Main), too many people get bitten by this.

Willy.


I have a multi-threaded C# console application that uses WMI
(System.Management namespace) to make RPC calls to several servers (600+ )
and returns ScheduledJobs. The section of my code that performs the query
is contained in a delegate function that I execute via a second
thread.
On
1
or 2 of the 600+ servers the query hangs. I've tried to use Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Based on other post I've read this is a common occurrence and the
only
way
to kill this thread is to use TerminateThread() located in the
Kernel32.dll.
I'm not really sure how to call this unmanaged code. Also
TerminateThread()
requires the thread's handle and I'm not sure how to obtain this in .NET.
I've made a "best guess" at the code but it doesn't work. See sample
below.
Can anyone give me a code sample of how this can be done? This is my
first
multi-threaded application and I'm pretty much a newbie to unmanaged code.


// This class allows me to pass a server name to the function
// and still call it as a delegate.

public class Parcer
{
public int ThreadID;
private string Server;
public DataSet ds;
public Parcer(string Server)
{
this.Server = Server;
}

public void ParceJobs()
{
ThreadID = AppDomain.GetCurrentThreadId();
IntelJobReader JobReader = new IntelJobReader();
//Instanciate
the
JobReader object. This is a class I wrote that make the WMI calls and
returns a DataSet.
DataSet JobSchedules = ( DataSet ) (
JobReader.GetSvrJobs(Server) );
this.ds = JobSchedules;
}
}

// This is my best guess at the unmanaged code. It runs without
error
but
does not terminate the thread.

public class Win32
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern int TerminateThread(int hThread);
}

// Excerpt from my Conseole App's Main code:

Parcer SchJobs = new Parcer(Server);
Thread JobTimeout = new Thread(new ThreadStart(SchJobs.ParceJobs));
JobTimeout.Start();
JobTimeout.Join(10000);
if (!JobTimeout.Join(10000))
{
JobTimeout.Abort(); // This will not terminate the thread
Win32.TerminateThread(AppDomain.GetCurrentThreadId());
Console.WriteLine("The thread timed out no change will be made
to
the
DB");
}

Thanks,
Bryan
 
W

Willy Denoyette [MVP]

Dave,

See inline ***


Dave said:
Actually I disagree. It's usually abused and used incorrectly but for some
applications there is no substitute. We only used it as an absolute last
resort but it was necessary (and we did understand all the downsides to
it).

*** Even Microsoft call this a dangerous API (see
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/terminatethread.asp),
and IMO it's a good thing there is no analog in the CLR.
In unmanaged world, if you know ALL the downsides, just go ahead no problem,
but what makes you so sure of that?.

When you call TerminateThread aside from the fact that the thread
terminates, you are guaranteed that:
- the process state is almost left in a corrupted state
- resources like, thread stack, TLS slots, per-thread data that libs are
keeping, synchronization primitives... are never released.
- DLL's loaded don't get their DllMain called.
- Locks held by the OS heap manager are not released
That seems like you are injecting a serious bug in your code whenever you
call ThreadTerminate, isn't that anough to say that you may as well kill the
process.

In managed code, things are getting a lot more complicated, as you correctly
stated in your previous reply, simply because you don't "control all of the
code that the target thread could possibly be running at the time of the
termination", you should never call ThreadAbort".

If the thread fails to exit when you signal it to using Thread.Abort() or
any other signal, it's probably :
- Waiting for IO rundown, hat is running code in kernel mode - or worse
running driver code; you can solve this by using async IO, using timeouts, e
tc... but terminating the thread while in this state can be very dangerous.
- It's busy working, the thread may never leave a locked/guarded block(s)
possibly causing deadlocks.
- The code contains a bug that prevents the thread to exit when signaled to
do so.

So, IMO when you think you need to call TerminateThread, you have a bug or a
design flaw in your code, in that case you better of to kill the process (or
unload the Application Domain) than to call TerminateThread.

IMO .NET wont be a suitable replacement for some Win32 apps until it has a
better story on a few key issues; aborting threads blocked in unmanaged
code, and uninterruptable finally blocks.
**** Uninterruptable finally blocks are addressed/solved in v 2.0.
is

I must be acronym challenged this morning; what does OP stand for?
*** Original Poster
the>
fact that some of the remote servers are unavailable or not responding, will

I don't understand those issues that well - I skipped over most of the COM
era and went from Win32 to .NET. What sorts of threading related issues can
you point out that I (everyone) should be aware of?
*** A lot of system services offered by the FCL are simply wrappers around
existing system services build/implemented in native code accessed through
COM interop, I know a number of these will be replaced by managed code
system services (like Indigo in Longhorn) in the (not so near) future. Now,
COM has always had his own threading issues like synchronization and inter
thread marshalling and message passing , great deal of these
issues/complexities are nicely handled by COM/COM+ itself (see apartments,
message pumps, access/activation control, security etc..) another part is
covered by the development tools, f.i VB5/6 only makes it possible to
produce single threaded apartment components, but most (if not all) of the
system COM services are or free threaded, or support both single and
mutithreaded environments.
The CLR has no notion of COM and has no concept of apartments for their
run-time context, this is still handled by COM which is per default loaded
by the hosting process (even before the CLR is loaded) . In .NET, most of
these COM complexities are hidden from you (the developer), by the FCL and
the CLR, you shouldn't even know that COM is used, it's nothing more than
an implementation detail. But the complexities still exist, and the CLR
can't handle all of them, so sometimes it's good to know what the
requirements are and possibly help the CLR a bit before we get bitten by
some nasty bugs.

Willy.
 
W

Willy Denoyette [MVP]

Dmitriy,
If the unmanaged code blocks (never returns), I would consider it as a bug
or at least a design flaws, calling TerminateThread wont solve these.
So if you regularery call TerminateThread, rest assured the process will be
left in a corrupted state and will die sooner or later.
You should only call "TerminateThread" if you control all of the code that
the target thread could possibly be running at the time of the termination,
in your example it's not the case so don't do it, terminating the process
(or unloading the AppDomain) is your only valid (but unfortunate)
alternative.

Willy.


Dmitriy Lapshin said:
Willy,

I was asking this because I am facing a similar problem. There's a managed
thread that does some work and should be able to be terminated at any time
by the user clicking on a kind of "Stop" button (like in IE). The thread to
be stopped is expected to mainly execute managed code, but it is not
guaranteed it will never use P/Invoke (the main part of the thread's
activity is running a third-party code I can make no assumptions of). In
this scenario, I believe there is no other way to stop the thread than
calling TerminateThread - of course when Thread.Abort() and Thread.Join
timed out.

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://x-unity.miik.com.ua/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

Willy Denoyette said:
It doesn't relate, my point was to forget about aborting a thread
asynchronously.
IMO, OP should take a look at the WMI related code, maybe WMI calls
could
be
done asynchronously i.s.o synchronously (blocking), that way you don't have
to try to abort a blocked thread (something that doesn't work after all,
unless by calling ThreadTerminate).

Willy.


in message news:[email protected]...
Hello Willy,

Another point to check is whether your code runs on a MTA thread (see
MTA/STAThread attribute on Main), too many people get bitten by this.

Could you please elaborate on this? I know what is STA and what is
MTA,
but
how does it related to aborting a worker thread?

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://x-unity.miik.com.ua/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

You should never call ThreadTerminate, it will corrupt the process, or
worse, if called while it holds a lock on the OS heap, all other threads
in
the system trying to allocate/free memory blocks from the same heap will
block forever.
Calling Thread.Abort() from another thread (asynch.) is also problematic:
1. When the thread is blocked in unmanaged code, Abort will suspend until
a
return from unmanaged code is done and a safe point for GC is reached.
2. Asynchronous Thread.Abort's should be deferred when executing a finally
clause, this is not done in v1.1, possibly resulting in resource
leaks
and
corrupted state.

I would suggest you revise the portion of your "Management/WMI"
code,
IMO
the solution should be found in there as it's the source of the problem
(blocking thread).
Another point to check is whether your code runs on a MTA thread (see
MTA/STAThread attribute on Main), too many people get bitten by this.

Willy.


I have a multi-threaded C# console application that uses WMI
(System.Management namespace) to make RPC calls to several servers
(600+ )
and returns ScheduledJobs. The section of my code that performs the
query
is contained in a delegate function that I execute via a second thread.
On
1
or 2 of the 600+ servers the query hangs. I've tried to use
Thread.Join()
coupled with a Thread.Abort() but this does not kill the thread.

Based on other post I've read this is a common occurrence and the only
way
to kill this thread is to use TerminateThread() located in the
Kernel32.dll.
I'm not really sure how to call this unmanaged code. Also
TerminateThread()
requires the thread's handle and I'm not sure how to obtain this in
.NET.
I've made a "best guess" at the code but it doesn't work. See sample
below.
Can anyone give me a code sample of how this can be done? This is my
first
multi-threaded application and I'm pretty much a newbie to unmanaged
code.


// This class allows me to pass a server name to the function
// and still call it as a delegate.

public class Parcer
{
public int ThreadID;
private string Server;
public DataSet ds;
public Parcer(string Server)
{
this.Server = Server;
}

public void ParceJobs()
{
ThreadID = AppDomain.GetCurrentThreadId();
IntelJobReader JobReader = new IntelJobReader(); //Instanciate
the
JobReader object. This is a class I wrote that make the WMI calls and
returns a DataSet.
DataSet JobSchedules = ( DataSet ) (
JobReader.GetSvrJobs(Server) );
this.ds = JobSchedules;
}
}

// This is my best guess at the unmanaged code. It runs without error
but
does not terminate the thread.

public class Win32
{
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern int TerminateThread(int hThread);
}

// Excerpt from my Conseole App's Main code:

Parcer SchJobs = new Parcer(Server);
Thread JobTimeout = new Thread(new ThreadStart(SchJobs.ParceJobs));
JobTimeout.Start();
JobTimeout.Join(10000);
if (!JobTimeout.Join(10000))
{
JobTimeout.Abort(); // This will not terminate the thread
Win32.TerminateThread(AppDomain.GetCurrentThreadId());
Console.WriteLine("The thread timed out no change will be made to
the
DB");
}

Thanks,
Bryan
 
D

Dave

See inline
*** Even Microsoft call this a dangerous API (see
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/terminatethread.asp),
and IMO it's a good thing there is no analog in the CLR.
In unmanaged world, if you know ALL the downsides, just go ahead no problem,
but what makes you so sure of that?.

When you call TerminateThread aside from the fact that the thread
terminates, you are guaranteed that:
- the process state is almost left in a corrupted state
- resources like, thread stack, TLS slots, per-thread data that libs are
keeping, synchronization primitives... are never released.
- DLL's loaded don't get their DllMain called.
- Locks held by the OS heap manager are not released
That seems like you are injecting a serious bug in your code whenever you
call ThreadTerminate, isn't that anough to say that you may as well kill the
process.

Yes, we were aware of all that (and more). Most of the threads that we
executed were written in a custom language (which we defined), and compiled
by a custom compiler (ours). User threads were prevented from acquiring any
of those resources you mentioned - the language was very constrained. Most
threads were completely within our control, and we injected lots of control
points into the execution stream so that when we wanted to terminate a
thread we could get it to a known safe point before we shut it down using
other techniques to make it block. However, there was also the possibility
that when the execution controller determined that a watchdog limit was
exceeded and the thread should be stopped, that for whatever reason a thread
would not reach that known safe point. Since this was controlling real-world
processes we simply had to make a choice, and the downside of allowing an
uncontrollable thread to continue to run was too great a risk. We jumped
through lots of hoops to try to coax it into returning to being
well-behaved, but in the end (the absolute very end) we terminated it.

We usually only had problems when we called into a DLL that was written by
an outside party. If we ran into a problem like this with our own code we
treated it as a serious bug that required an instant bugfix. In actual
practice this was very rare (we usually had to contrive it), and I never did
come across a situation that resulted in the type of system corruption that
would require us to reboot. We also had lots of code to detect internal
corruption and to shut ourselves down in that event. We also had our own
internal debate along the same lines that you've put forth. It was a very
controversial subject.

I agree that it's just as well there is no counterpart in the CLR. The CLR
isn't suitable for this type of control anyway (at least, not yet). If they
ever get a version of the CLR to run in the kernel then its time to expose a
TerminateThread API. Long before I'll look for a TerminateThread API I'd
rather see a thread control environment more amenable for control purposes
(f.e. more priority levels - 5 is a joke).

In managed code, things are getting a lot more complicated, as you correctly
stated in your previous reply, simply because you don't "control all of the
code that the target thread could possibly be running at the time of the
termination", you should never call ThreadAbort".
Agreed. There are too many other means of signalling a thread, unless you
are just plain lazy.
If the thread fails to exit when you signal it to using Thread.Abort() or
any other signal, it's probably :
- Waiting for IO rundown, hat is running code in kernel mode - or worse
running driver code; you can solve this by using async IO, using timeouts,

You can do this if you write the code yourself, but if all you have is an
API that doesn't expose an async mechanism you are at their mercy. There are
lots of APIs that do something like wait for user input before returning. If
that input never comes the API never returns ==> hang.
etc... but terminating the thread while in this state can be very
dangerous.- It's busy working, the thread may never leave a locked/guarded
block(s)
possibly causing deadlocks.
- The code contains a bug that prevents the thread to exit when signaled to
do so.

So, IMO when you think you need to call TerminateThread, you have a bug or a
design flaw in your code, in that case you better of to kill the process (or
unload the Application Domain) than to call TerminateThread.

I think you misunderstand me. I am not advocating using TerminateThread
(especially from within .NET), exactly the opposite. As I stated earlier,
dumping the AppDomain usually works, and when it doesn't usually the other
recourse is to exit the app and correct the problem. I'd like to see the CLR
team work on this; it's the source of a lot of problems.

My only point was that in some cases, when you understand the issues and are
willing to deal with them, even dangerous APIs have their uses. And I'll end
this with the observation that this API has been in Win32 for over 10
years...if it was really such that it should never be called under any
circumstances then the Win32 group should have deprecated this API years
ago.

**** Uninterruptable finally blocks are addressed/solved in v 2.0.

THAT will be a big plus.


*** A lot of system services offered by the FCL are simply wrappers around
existing system services build/implemented in native code accessed through
COM interop, I know a number of these will be replaced by managed code
system services (like Indigo in Longhorn) in the (not so near) future. Now,
COM has always had his own threading issues like synchronization and inter
thread marshalling and message passing , great deal of these
issues/complexities are nicely handled by COM/COM+ itself (see apartments,
message pumps, access/activation control, security etc..) another part is
covered by the development tools, f.i VB5/6 only makes it possible to
produce single threaded apartment components, but most (if not all) of the
system COM services are or free threaded, or support both single and
mutithreaded environments.
The CLR has no notion of COM and has no concept of apartments for their
run-time context, this is still handled by COM which is per default loaded
by the hosting process (even before the CLR is loaded) . In .NET, most of
these COM complexities are hidden from you (the developer), by the FCL and
the CLR, you shouldn't even know that COM is used, it's nothing more than
an implementation detail. But the complexities still exist, and the CLR
can't handle all of them, so sometimes it's good to know what the
requirements are and possibly help the CLR a bit before we get bitten by
some nasty bugs.

I understand Win32 threading fairly well but I never had gotten my head
wrapped around apartments and the weird COM threading models. I like the
fact that .NET makes most of those hassles go away so that we are back to
plain old threading again. Now the biggest problem I run into is convincing
all those people with a vested interest in COM components that they should
give it up and move into .NET. There's still a lot of resistance to that.
 
W

Willy Denoyette [MVP]

Dave,

Inline

I think you misunderstand me. I am not advocating using TerminateThread
(especially from within .NET), exactly the opposite. As I stated earlier,
dumping the AppDomain usually works, and when it doesn't usually the other
recourse is to exit the app and correct the problem. I'd like to see the CLR
team work on this; it's the source of a lot of problems.
No, I know you are not advocating using TerminateThread, and from reading
your (interesting) replies, I'm pretty confident you know exactly what you
are talking about.
My only point was that in some cases, when you understand the issues and are
willing to deal with them, even dangerous APIs have their uses. And I'll end
this with the observation that this API has been in Win32 for over 10
years...if it was really such that it should never be called under any
circumstances then the Win32 group should have deprecated this API years
ago.
Sure they have their uses, but as you probably know, API's like
TerminateThread are only recently called "dangerous", just because many of
us had the oportunity to discover the "dangers". Now, the TerminateThread
service is there and can't be removed from existing OS'ses, so it's
important to know there is no use of it in managed code, and you should only
consider it for very special cases like the one you pictured.


I understand Win32 threading fairly well but I never had gotten my head
wrapped around apartments and the weird COM threading models. I like the
fact that .NET makes most of those hassles go away so that we are back to
plain old threading again. Now the biggest problem I run into is convincing
all those people with a vested interest in COM components that they should
give it up and move into .NET. There's still a lot of resistance to that.

Getting rid of COM is something that will takes years (maybe decades), and
basically there is nothing wrong with it. I even like the idea of COM being
used as a system level component architecture for the years to come, but at
the application level, one should try to get rid of it, or at least design
your interfaces so you can easely get rid of the requirements imposed by COM
at a later stage without breaking your clienst code.


Willy.
 
D

Dave

Sure they have their uses, but as you probably know, API's like
TerminateThread are only recently called "dangerous", just because many of
us had the oportunity to discover the "dangers". Now, the TerminateThread
service is there and can't be removed from existing OS'ses, so it's
important to know there is no use of it in managed code, and you should only
consider it for very special cases like the one you pictured.
I agree completely.
Getting rid of COM is something that will takes years (maybe decades), and
basically there is nothing wrong with it. I even like the idea of COM being
used as a system level component architecture for the years to come, but at
the application level, one should try to get rid of it, or at least design
your interfaces so you can easely get rid of the requirements imposed by COM
at a later stage without breaking your clienst code.

Heck, we still sell the occasional copy of the 16 bit DDE server code I
wrote over a decade ago, so I expect COM will be around for quite a while. I
still get into debates about whether or not it's a good idea to use the
registry as a store for every application's configuration data, and I
haven't even started to talk to them about transitioning from error return
values to using exceptions. Convincing these people to abandon the tools and
systems they're comfortable with will take quite a while. Change is hard.

cheers,
Dave
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top