thread.Abort()

D

Daisy

From this page:
http://www.c-sharpcorner.com/2/mt_beginner1.asp

Thread class's Abort method is called to kill a thread permanently. Make
sure you call IsAlive before Abort.

if ( thread.IsAlive )
{
thread.Abort();
}

My question is, what happens if the thread finished what it was doing
between IsAlive being checked, and Abort() being called?

Threading isn't the only place I've seen things like this, and I've always
just assumed they'd thought about it (and it was unlikely anyhow), but I
know we don't write applications by saying "nah, it'll never happen" and now
I'm curious!
 
D

Dave

Daisy said:
From this page:
http://www.c-sharpcorner.com/2/mt_beginner1.asp

Thread class's Abort method is called to kill a thread permanently. Make
sure you call IsAlive before Abort.

if ( thread.IsAlive )
{
thread.Abort();
}

My question is, what happens if the thread finished what it was doing
between IsAlive being checked, and Abort() being called?

I don't know what the author was thinking when he made that statement but
you are correct (IMO) for being suspicious of it. The code snippet does
nothing to detect or prevent race conditions, and I'm not sure why he feels
it necessary to test for that condition anyway. There are many reasons for
not using Thread.Abort anyway.
Threading isn't the only place I've seen things like this, and I've always
just assumed they'd thought about it (and it was unlikely anyhow), but I
know we don't write applications by saying "nah, it'll never happen" and now
I'm curious!
You are correct; there are many code snippets that ignore race conditions.
Writing correct multithreaded code is a very difficult task and even
thoroughly-tested production code can have threading bugs lurking in it.
There are also many people who think they know the issues but really don't.

Dave
 
D

Daisy

You are correct; there are many code snippets that ignore race conditions.
Writing correct multithreaded code is a very difficult task and even
thoroughly-tested production code can have threading bugs lurking in it.
There are also many people who think they know the issues but really
don't.

Righto. But how *would* you overcome something like this? Say you wanted to
read a property from an object you're not sure still exists. You test it
exists first, but you've still got a race condition. Wrapping it in a try
block would work, but is that the best way?
 
J

Jeffrey Wynn

It has been my experience that calling Abort() on a thread that already has
been terminated doesn't cause an exception to be thrown. Run the following
code below for an example. Calling IsAlive() is a good practice.

using System;
using System.Threading;

namespace ConsoleTester
{
/// <summary>
/// Summary description for Class1.
/// </summary>

class Test
{
public static void Main()
{
Thread newThread = new Thread( new ThreadStart( TestMethod ) );
newThread.Start();
Thread.Sleep( 1000 );

// Abort newThread.
Console.WriteLine( "Main aborting new thread." );
newThread.Abort( "Information from Main." );

// Wait for the thread to terminate.
newThread.Join();
Console.WriteLine( "New thread terminated - Main exiting." );
Console.ReadLine();
}

static void TestMethod()
{
try
{
//while( true )
{
Console.WriteLine( "New thread running." );
//Thread.Sleep( 1000 );
}
Console.WriteLine( "New thread exiting..." );
}
catch( ThreadAbortException abortException )
{
Console.WriteLine( (string) abortException.ExceptionState );
}
}
}

}

Hope this helps.
 
D

Daisy

Jeffrey Wynn said:
It has been my experience that calling Abort() on a thread that already has
been terminated doesn't cause an exception to be thrown. Run the following
code below for an example. Calling IsAlive() is a good practice.

If it doesn't throw an exception (and doesn't work anyway), why bother
checking? Surely it's just a waste of time?
 
J

Jeffrey Wynn

Perhaps for code where performance isn't a critical issue, calling Abort()
without checking might not cause a problem. Basically checking, and not
calling Abort(), saves the CLR from performing some internal actions based
on your request.

Also, there are times when calling Abort() won't end the thread (such as
when your thread is blocked in unmanaged code - waiting on a socket, for
example) as the ThreadAbortException is a managed construct. In these
circumstances, it is also a good idea to call IsAlive() after the Abort()
has been called to see if further action is required. Of course calling
Join() with a timeout is also an alternative to calling IsAlive() in this
circumstance.

Hope this helps.
 
D

Daisy

Jeffrey Wynn said:
Perhaps for code where performance isn't a critical issue, calling Abort()
without checking might not cause a problem. Basically checking, and not
calling Abort(), saves the CLR from performing some internal actions based
on your request.

Also, there are times when calling Abort() won't end the thread (such as
when your thread is blocked in unmanaged code - waiting on a socket, for
example) as the ThreadAbortException is a managed construct. In these
circumstances, it is also a good idea to call IsAlive() after the Abort()
has been called to see if further action is required. Of course calling
Join() with a timeout is also an alternative to calling IsAlive() in this
circumstance.

Hope this helps.

All makes sense, thanks :blush:)
 
D

Dave

Daisy said:
don't.

Righto. But how *would* you overcome something like this? Say you wanted to
read a property from an object you're not sure still exists. You test it
exists first, but you've still got a race condition. Wrapping it in a try
block would work, but is that the best way?
--

If you have a reference to an object then the object will be around so long
as you hang onto the reference. The issue is not whether the memory is still
valid or not - as long as the reference is rooted the memory is still
valid - the original issue is one of race conditions between threads.

A try block does not help prevent race conditions, it only catches an
exception that is thrown in the guarded block of code. The only way to
prevent race conditions is to use synchronization mechanisms; the code
snippet shown does absolutely nothing in this regard.

Further, the entire premise of the code snippet shown is incorrect. There
are many side-effects to inducing an abort exception asynchronously in
another thread, all of them bad. For example, the target thread may be
executing code in a finally block - this can be interrupted with unknown
consequences. Another is that if the exception occurs while the target
thread is executing code in a static constructor the type is rendered
unusable in that appdomain.

In addition thread objects continue to exist for some time even after the
thread is no longer "alive" (holding a reference to the thread will do
this), and if you call abort on a thread that is already terminated the
request is ignored, so I still am mystified as to why the author of that
article thought it necessary to call IsAlive prior to calling Abort.

In the snippet...

if ( t.IsAlive )
t.Abort();

The amount of time that can elapse after calling IsAlive and before
Thread.Abort is executed is unbounded. The call to IsAlive can indicate the
target thread is alive but before the next line of code executes a context
switch can occur, other code executes, and the target thread could actually
die. Even if the thread is still alive the amount of time it takes for the
thread to actually terminate is also unbounded.

One safe way for one thread to signal another thread to terminate is to use
a signalling mechanism, such as a ManualResetEvent, that the calling thread
sets to the signalled state and the target threads periodically checks. This
is a synchronous mechanism that allows the target thread to reach a known
safe point in its execution path before it terminates. This is a relatively
standard technique. If you need to know when the thread has terminated you
can wait on the thread object to become signalled (do a Join on the thread
object).

Dave
 
D

Daisy

Dave said:
If you have a reference to an object then the object will be around so long
as you hang onto the reference. The issue is not whether the memory is still
valid or not - as long as the reference is rooted the memory is still
valid - the original issue is one of race conditions between threads.

If the reference has been set to null it won't :p

I was thinking something like:

if (myObject.SomeParam != null)
{
myObject.SomeParam.DoSomething();
}

Another thread may have set SomeParam to a null in between.

I guess it'll all be covered under synchronisation? I don't need it now, but
when I do, I'll have to do some reading up!
 
D

Dave

If the reference has been set to null it won't :p
I was thinking something like:

if (myObject.SomeParam != null)
{
myObject.SomeParam.DoSomething();
}

Another thread may have set SomeParam to a null in between.

Now I see what you are getting at. If you have more then 1 thread that can
modify an object then you need to guard access to the object with a
synchronization object, such as a mutex or monitor. A very simple pattern
is...

lock( aPrivateObjectThatProtectsAccessToTheRealObject )
{
// access the object
if (myObject.SomeParam != null)
{
myObject.SomeParam.DoSomething();
}
}

This is very basic but for simple situations should work adequately. There
are a number of very good books on the general subject of threading and
synchronization you can refer to.
I guess it'll all be covered under synchronisation? I don't need it now, but
when I do, I'll have to do some reading up!

Yup. Enjoy.
 
D

Daisy

Dave said:
Now I see what you are getting at. If you have more then 1 thread that can
modify an object then you need to guard access to the object with a
synchronization object, such as a mutex or monitor. A very simple pattern
is...

lock( aPrivateObjectThatProtectsAccessToTheRealObject )
{
// access the object
if (myObject.SomeParam != null)
{
myObject.SomeParam.DoSomething();
}
}

This is very basic but for simple situations should work adequately. There
are a number of very good books on the general subject of threading and
synchronization you can refer to.

Righto, that makes sense now, I'll have a read up. But a quick q?... The
above code, if another thread has an object locked, will it just block until
it's unlocked?

Thanks for your replies :blush:)
 
D

Dave

lock( aPrivateObjectThatProtectsAccessToTheRealObject )
{
// access the object
if (myObject.SomeParam != null)
{
myObject.SomeParam.DoSomething();
}
}
Righto, that makes sense now, I'll have a read up. But a quick q?... The
above code, if another thread has an object locked, will it just block until
it's unlocked?
Yes, that's exactly correct. There are more advanced issues that this simple
sample does not show, like deadlocks, inter-process synchronization,
priority inversion, wait timeouts, what happens when a thread that owns a
lock is terminated, etc. but this is a good starting place.
 
D

Daisy

Dave said:
Yes, that's exactly correct. There are more advanced issues that this simple
sample does not show, like deadlocks, inter-process synchronization,
priority inversion, wait timeouts, what happens when a thread that owns a
lock is terminated, etc. but this is a good starting place.

Yep, understood. Thanks 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