By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,701 Members | 1,978 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,701 IT Pros & Developers. It's quick & easy.

Thread.Abort

P: n/a
Hi

I wrote an application server (a remoting sinlgeton), where processes must
be stopped in very rare cases, done thru a Thread.Abort(). Occasionally, and
only after a Thread.Abort(), this component becomes instabile, throwing a
Windows like error (access violation on 0x00000002), not an framework
exception. The component and all of its subcomponents are 100% managed code.
What could go wrong with Thread.Abort()?

Thanks for any hints.
Urs
Nov 17 '05 #1
Share this Question
Share on Google+
18 Replies


P: n/a
Thread.Abort() is a method you should only call to abort the current thread,
the only valid reason to call it on another thread is when you intend to
unload the application domain anyway.
There are numerous things that can go wrong when aborting another thread,
Please search the archives, this has been discussed several times before in
this and other NG's.

Willy.

"Urs Vogel" <uv****@msn.com> wrote in message
news:%2****************@TK2MSFTNGP12.phx.gbl...
Hi

I wrote an application server (a remoting sinlgeton), where processes must
be stopped in very rare cases, done thru a Thread.Abort(). Occasionally,
and only after a Thread.Abort(), this component becomes instabile,
throwing a Windows like error (access violation on 0x00000002), not an
framework exception. The component and all of its subcomponents are 100%
managed code. What could go wrong with Thread.Abort()?

Thanks for any hints.
Urs

Nov 17 '05 #2

P: n/a
Is your app server interacting with any system resources? That could cause
this.
Look into ManualResetEvent class, it's a call that can signal a running
thread that something important happened (user clicked cancel for example)
and it can abort gracefully. I remember reading an article with code samples
on how to do that, can't remember where.

"Urs Vogel" wrote:
Hi

I wrote an application server (a remoting sinlgeton), where processes must
be stopped in very rare cases, done thru a Thread.Abort(). Occasionally, and
only after a Thread.Abort(), this component becomes instabile, throwing a
Windows like error (access violation on 0x00000002), not an framework
exception. The component and all of its subcomponents are 100% managed code.
What could go wrong with Thread.Abort()?

Thanks for any hints.
Urs

Nov 17 '05 #3

P: n/a
Or upgrade to .NET Framework 2.0 where this issue has been fixed!

On Tue, 16 Aug 2005 17:27:27 +0200, "Willy Denoyette [MVP]"
<wi*************@telenet.be> wrote:
Thread.Abort() is a method you should only call to abort the current thread,
the only valid reason to call it on another thread is when you intend to
unload the application domain anyway.
There are numerous things that can go wrong when aborting another thread,
Please search the archives, this has been discussed several times before in
this and other NG's.

Willy.

--
http://www.kynosarges.de
Nov 17 '05 #4

P: n/a

"Christoph Nahr" <ch************@kynosarges.de> wrote in message
news:dn********************************@4ax.com...
Or upgrade to .NET Framework 2.0 where this issue has been fixed!

On Tue, 16 Aug 2005 17:27:27 +0200, "Willy Denoyette [MVP]"
<wi*************@telenet.be> wrote:
Thread.Abort() is a method you should only call to abort the current
thread,
the only valid reason to call it on another thread is when you intend to
unload the application domain anyway.
There are numerous things that can go wrong when aborting another thread,
Please search the archives, this has been discussed several times before
in
this and other NG's.

Willy.

--
http://www.kynosarges.de


True, but I don't believe all issues are fixed, as far as I know
Thread.Abort() will no longer be injected while running exception handling
code blocks, but will be delayed until catch/finally blocks exit, but the
issues remain when executing outside try/catch/finally blocks.

Willy.

Nov 17 '05 #5

P: n/a
On Wed, 17 Aug 2005 10:44:04 +0200, "Willy Denoyette [MVP]"
<wi*************@telenet.be> wrote:
True, but I don't believe all issues are fixed, as far as I know
Thread.Abort() will no longer be injected while running exception handling
code blocks, but will be delayed until catch/finally blocks exit, but the
issues remain when executing outside try/catch/finally blocks.


What issues would that be? The interruption of catch/finally was the
only one that I'm aware of. Certainly Thread.Abort will stop your
thread asynchronously, interrupting whatever it is doing outside of
exception handling -- but that's the whole point of it, after all.
--
http://www.kynosarges.de
Nov 17 '05 #6

P: n/a

"Christoph Nahr" <ch************@kynosarges.de> wrote in message
news:s9********************************@4ax.com...
On Wed, 17 Aug 2005 10:44:04 +0200, "Willy Denoyette [MVP]"
<wi*************@telenet.be> wrote:
True, but I don't believe all issues are fixed, as far as I know
Thread.Abort() will no longer be injected while running exception handling
code blocks, but will be delayed until catch/finally blocks exit, but the
issues remain when executing outside try/catch/finally blocks.
What issues would that be? The interruption of catch/finally was the
only one that I'm aware of. Certainly Thread.Abort will stop your
thread asynchronously, interrupting whatever it is doing outside of
exception handling -- but that's the whole point of it, after all.
--

The general issue of reliability remains as long as one thread can
arbitrarily inject an abort into another thread. For example, if a static
constructor is aborted it renders that type unusable within that appdomain -
an instance of that type cannot be constructed. Outside of constrained
execution regions an abort can be raised between any two lines of machine
code, so it is very difficult to determine if code is correct.

This may not be a problem if you are expecting this behavior, but it is
easy for the unwary to make assumptions that are incorrect.

http://www.kynosarges.de

Nov 17 '05 #7

P: n/a
On Wed, 17 Aug 2005 18:26:25 -0500, "David Levine"
<no******************@wi.rr.com> wrote:
The general issue of reliability remains as long as one thread can
arbitrarily inject an abort into another thread. For example, if a static
constructor is aborted it renders that type unusable within that appdomain -
an instance of that type cannot be constructed.
You're right, it's still possible to abort a static constructor.
However, I believe that's only a problem if a new thread accesses such
types with static ctors for the first time. It's a potentially nasty
issue that should be fixed; but it shouldn't affect your typical
background worker thread that only operates on existing data when the
program is already fully initialized.
Outside of constrained
execution regions an abort can be raised between any two lines of machine
code, so it is very difficult to determine if code is correct.
Sure, but since catch/finally is now left alone it's at least possible
to mitigate this issue with the appropriate constructs.
This may not be a problem if you are expecting this behavior, but it is
easy for the unwary to make assumptions that are incorrect.


Well, as I already said Thread.Abort is specifically intended for
asynchronously terminating another thread, so this behavior should be
expected by anyone who is using this facility. MT is and will remain
hard, and always requires that developers learn how it works and are
careful about their implementation. The behavior of Thread.Abort is
just another facet that we'll have to remember.
--
http://www.kynosarges.de
Nov 17 '05 #8

P: n/a

"Christoph Nahr" <ch************@kynosarges.de> wrote in message
news:s9********************************@4ax.com...
On Wed, 17 Aug 2005 10:44:04 +0200, "Willy Denoyette [MVP]"
<wi*************@telenet.be> wrote:
True, but I don't believe all issues are fixed, as far as I know
Thread.Abort() will no longer be injected while running exception handling
code blocks, but will be delayed until catch/finally blocks exit, but the
issues remain when executing outside try/catch/finally blocks.


What issues would that be? The interruption of catch/finally was the
only one that I'm aware of. Certainly Thread.Abort will stop your
thread asynchronously, interrupting whatever it is doing outside of
exception handling -- but that's the whole point of it, after all.
--
http://www.kynosarges.de


Well, my point was that you shouldn't assume it's safe to continue
execution of code inside an AD that has been subject of an asynchronous
thread abort, that's the impression you gave by this "Or upgrade to .NET
Framework 2.0 where this issue has been fixed!". NO, you still have to
consider thread aborts as being initiated by AD unloads, asynchronous thread
aborts initiated by a call to Thread.Abort() in your code is still bad,
unless it's immediately followed by an AD unload.

Now what's been solved, is that the CLR no longer injects (asynchronous)
thread aborts while executing inside class contructors, finally and catch
blocks and while running unmanaged code. If an abort is requested while
executing inside one of these, the CLR will inject as soon as you exit from
these regions, it means that you are assured that static's are correctly
initialized and that your exception handlers will run. So now at least you
have a fair chance to fix up your cross-AD state, this covers state
acquired/mutated inside a try block, so you can continue to run your other
AD and possibly recycle the offending AD without being forced to recycle the
process (like it's been done in ASP.NET).
However , you still have to consider state acquired outside a try block,
where a thread abort can occur between any machine instruction.

That means that following will leak a handle when the abort occurs after the
handle has been acquired but before the try block has entered.

IntPtr handle = AcquireHandle(....)
try {
// use add...
....}
finally {
FreeUnmanaged(handle);
}
Now, suppose handle is a File handle, when you recycle the AD domain and try
to open same File (or simply try to open the file in another process/AD) you
might get a sharing violation exception because the file wasn't closed as
the process didn't exit.

You can solve this by pairing the allocation/de-allocation unmanaged
resources (handles, memory etc...) inside the try/finally, or by using a
SafeHandle wrapper for handles.

But consider this ...
using(SomeExpensiveResource res = new(....))
{
....
}
a thread abort can be raised after the constructor invocation but before
the assignment of res, as this abort occurs outside the try block, finally
never runs and Dispose is never called. (Note that res == null, so Dispose
could never be called anyway).
Hopefully SomeExpensiveResource has a Finalizer or you'll leak resources,
that's one of the reasons why IDisposable objects should have a destructor
(Finalize).

Willy.


Nov 17 '05 #9

P: n/a
Is the Thread Abort injection postponed only till the catch/finally
block completes, or is it held back till the entire try block and it's
catch/finally blocks execute?

Regards
Senthil

Nov 17 '05 #10

P: n/a

"S. Senthil Kumar" <se**************@gmail.com> wrote in message
news:11**********************@g14g2000cwa.googlegr oups.com...
Is the Thread Abort injection postponed only till the catch/finally
block completes, or is it held back till the entire try block and it's
catch/finally blocks execute?

Regards
Senthil


No, the thread abort exception is not postponed while running inside a try
block, this behavior did not change. That means that code execution is
stopped cold and the CLR starts unwinding the thread with an ... undeniable
ThreadAbortException that is propagated in a normal fashion till it reaches
the threads most base stack frame, after which the thread exits.

Willy.
Nov 17 '05 #11

P: n/a
On Thu, 18 Aug 2005 12:22:02 +0200, "Willy Denoyette [MVP]"
<wi*************@telenet.be> wrote:
Well, my point was that you shouldn't assume it's safe to continue
execution of code inside an AD that has been subject of an asynchronous
thread abort, that's the impression you gave by this "Or upgrade to .NET
Framework 2.0 where this issue has been fixed!". NO, you still have to
consider thread aborts as being initiated by AD unloads, asynchronous thread
aborts initiated by a call to Thread.Abort() in your code is still bad,
unless it's immediately followed by an AD unload.
??? I completely disagree, and I don't really see any reasons to make
such broad-sweeping statements.
Now what's been solved, is that the CLR no longer injects (asynchronous)
thread aborts while executing inside class contructors, finally and catch
blocks and while running unmanaged code.
So now it's safe even for static constructors? That's fantastic, I
wasn't aware of that! That solves the last real issue I know of.
However , you still have to consider state acquired outside a try block,
where a thread abort can occur between any machine instruction.
Sure, but that's simply because Thread.Abort raises an *asynchronous*
exception, and you have to be aware exactly what that means. I really
can't see why that should be a reason to avoid it, though.
That means that following will leak a handle when the abort occurs after the
handle has been acquired but before the try block has entered.


Yeah, but forgive me, isn't that just saying "bad programming is bad"?
Where a ThreadAbortException is possible you just must not do that.
It's another rule to remember and follow, but not an impossible one.
--
http://www.kynosarges.de
Nov 17 '05 #12

P: n/a

"Christoph Nahr" <ch************@kynosarges.de> wrote in message
news:93********************************@4ax.com...
On Thu, 18 Aug 2005 12:22:02 +0200, "Willy Denoyette [MVP]"
<wi*************@telenet.be> wrote:
Well, my point was that you shouldn't assume it's safe to continue
execution of code inside an AD that has been subject of an asynchronous
thread abort, that's the impression you gave by this "Or upgrade to .NET
Framework 2.0 where this issue has been fixed!". NO, you still have to
consider thread aborts as being initiated by AD unloads, asynchronous
thread
aborts initiated by a call to Thread.Abort() in your code is still bad,
unless it's immediately followed by an AD unload.
??? I completely disagree, and I don't really see any reasons to make
such broad-sweeping statements.


Why? because you don't like it or you because you think I'm wrong. If it's
the latter we will have to agree to disagree.
Maybe it's too strongly worded, but following is what's been suggested by
devs. on the CLR team (C Brumme, J. Duffy) and outside Microsoft; "Most code
should never try to abort an opaque thread..." "It's recommended that
Framework code is written with the assumption that an abort will shortly be
followed by a AD unload".

Now what's been solved, is that the CLR no longer injects (asynchronous)
thread aborts while executing inside class contructors, finally and catch
blocks and while running unmanaged code.


So now it's safe even for static constructors? That's fantastic, I
wasn't aware of that! That solves the last real issue I know of.


Really and what about this:

using(Resource r = new(...)
{
...
}
where the resource acquisition occurs outside the try block (if you look at
what's been emitted by the C# compiler), that means that finally won't run
(Dispose won't be called) in the presence of an Asynchronous exception like
ThreadAbort that occurs after acquiring but before assignment of the
reference to r, there goes your deterministic clean-up, so you are at the
mercy of the finalizer to release the resource acquired.
However , you still have to consider state acquired outside a try block,
where a thread abort can occur between any machine instruction.


Sure, but that's simply because Thread.Abort raises an *asynchronous*
exception, and you have to be aware exactly what that means. I really
can't see why that should be a reason to avoid it, though.


Maybe <be aware exactly what that means> is the reason why you can't see a
reason to avoid it.

Lets look at another sample....
Suppose you are interrupted by a thread abort while modifying a complex data
structure (a container), leaving the container in a partly modified state.
Your container is corrupted, right?
No problem you say, the GC will clean-up the garbage when there is only one
single reference, but what if this container was shared between threads? How
does the thread knows the container is in a corrupted state? It doesn't,
unless the thread calling Thread.Abort is also the thread that has a
reference to the shared object and simply recovers the object state somehow.
But what when more threads share the object......

That means that following will leak a handle when the abort occurs after
the
handle has been acquired but before the try block has entered.


Yeah, but forgive me, isn't that just saying "bad programming is bad"?


Why?
Do you assume this is better programming?

IntPtr handle = IntPtr.Zero;
try {
handle = AcquireHandle(....); // Abort after acquiring but before
assigning to handle
...
}
finally {
if(handle != IntPtr.Zero) FreeUnmanaged(handle); // handle is
null, so handle leak
}
or this....
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(100000);
}
finally
{
if(ptr!= IntPtr.Zero)
Marshal.FreeHGlobal(ptr);
}

No it isn't, if the abort occurs after memory allocation but before ptr
assignment, you'll end with ptr still being "null" when your finally runs,
bummer memory leak. This isn't an issue when you unload the AD, but what if
you continue to execute code inside this domain?
Where a ThreadAbortException is possible you just must not do that.
That's the point of asynchronous exceptions, they might occur at any time.
It's another rule to remember and follow, but not an impossible one.


No, for me rule to remember is "Never initiate asynchronous thread aborts in
Framework code, unless it's part of an AD unload", there are more secure
alternatives to stop a thread from making progress.

Willy.
Nov 17 '05 #13

P: n/a
On Fri, 19 Aug 2005 00:34:17 +0200, "Willy Denoyette [MVP]"
<wi*************@telenet.be> wrote:
Why? because you don't like it or you because you think I'm wrong. If it's
the latter we will have to agree to disagree.
Maybe it's too strongly worded, but following is what's been suggested by
devs. on the CLR team (C Brumme, J. Duffy) and outside Microsoft; "Most code
should never try to abort an opaque thread..." "It's recommended that
Framework code is written with the assumption that an abort will shortly be
followed by a AD unload".
I think the key word here is "an *opaque* thread". If this means "a
thread whose code you don't know" then I'll agree. That's no reason
not to use Thread.Abort on threads whose code you know, though.
Really and what about this:

using(Resource r = new(...)
{
..
}
where the resource acquisition occurs outside the try block (if you look at
what's been emitted by the C# compiler), that means that finally won't run
(Dispose won't be called) in the presence of an Asynchronous exception like
ThreadAbort that occurs after acquiring but before assignment of the
reference to r, there goes your deterministic clean-up, so you are at the
mercy of the finalizer to release the resource acquired.
I admit that's a tricky issue but the solution is simple -- use
explicit try/finally instead. And since the finalizer *will* release
the resource eventually I don't see why this is such a big issue.

But the real problem here is the possibility of interrupting the
assignment expression which you mention below.
Suppose you are interrupted by a thread abort while modifying a complex data
structure (a container), leaving the container in a partly modified state.
Your container is corrupted, right?
No problem you say, the GC will clean-up the garbage when there is only one
single reference, but what if this container was shared between threads?
If there's any chance of asynchronous interruptions then obviously the
background threads must not modify shared containers; they should
modify private copies which are then copied back to the main thread
when calculation is complete and known to have succeeded.

Alternatively, they could invoke back to the main thread for making
changes. Usually you can't just secretly modify shared data in
another thread anyway since some part of the main thread needs to know
about the change, update related data or the UI or whatever.

(As an aside, this is also one reason why I believe the old
Synchronized wrappers for the non-generic collections were a horrible,
horrible idea. They might trick people into doing exactly what you
propose here, assuming that everything is "thread-safe" because the
documentation says so...)
No it isn't, if the abort occurs after memory allocation but before ptr
assignment, you'll end with ptr still being "null" when your finally runs,
bummer memory leak. This isn't an issue when you unload the AD, but what if
you continue to execute code inside this domain?
Okay, that's a really good point. Hmm... I suppose the only way to
avoid this is to not allocate any critical resources within code
blocks where Thread.Abort is possible. You could always use Monitor
locks to protect such blocks, though; or allocate resources in the
main thread before handing the references over to the worker thread.

The possibility of a ThreadAbortException interrupting a reference
assignment is really aggravating, though. I'd say that calls for some
kind of IL primitive that prevents a statement sequence from being
interrupted. Since the Framework team already figured out how to
protect static ctors and catch/finally blocks that should be possible.
No, for me rule to remember is "Never initiate asynchronous thread aborts in
Framework code, unless it's part of an AD unload", there are more secure
alternatives to stop a thread from making progress.


But not asynchronously, which is the point. With any alternative
method, the thread that is to be stopped must actively check for some
kind of signal. That may be very difficult to implement if your
thread is doing some complex and lengthy computation.
--
http://www.kynosarges.de
Nov 17 '05 #14

P: n/a

"Christoph Nahr" <ch************@kynosarges.de> wrote in message
news:ct********************************@4ax.com...
On Fri, 19 Aug 2005 00:34:17 +0200, "Willy Denoyette [MVP]"
<wi*************@telenet.be> wrote:

I think the key word here is "an *opaque* thread". If this means "a
thread whose code you don't know" then I'll agree.
Aren't most of the threads opaque in that sense, do you exactly know what
happens under the covers of a BCL or FCL method call.

That's no reason not to use Thread.Abort on threads whose code you know, though.
Really and what about this:

using(Resource r = new(...)
{
..
}
where the resource acquisition occurs outside the try block (if you look
at
what's been emitted by the C# compiler), that means that finally won't run
(Dispose won't be called) in the presence of an Asynchronous exception
like
ThreadAbort that occurs after acquiring but before assignment of the
reference to r, there goes your deterministic clean-up, so you are at the
mercy of the finalizer to release the resource acquired.
I admit that's a tricky issue but the solution is simple -- use
explicit try/finally instead. And since the finalizer *will* release
the resource eventually I don't see why this is such a big issue.


So what you are suggesting is to forget about the compiler support offered
through the 'using' keyword and go back to coding try/finaly blocks by hand,
no thank you. And this is the idea of the FCL devs. either. The FCL are
written with the assumption that an abort will shortly be followed by a AD
unload, so they don't (and can't) take care of non-cross AD state. The CLR
devs. have gone to a great length (See - CER, Reliability contracts,
SafeHandles etc..) to increase the reliability of the system and assure you
have a fair chance to recover from AD unloads and its implied thread aborts
without the need to recycle the hosting process, but this doesn't mean you
are safe to continue to run code in an AD that was subject of an
asynchronous exception.
But the real problem here is the possibility of interrupting the
assignment expression which you mention below.
Not only this assignment, but all possible assignments should be made
atomic.
Suppose you are interrupted by a thread abort while modifying a complex
data
structure (a container), leaving the container in a partly modified state.
Your container is corrupted, right?
No problem you say, the GC will clean-up the garbage when there is only
one
single reference, but what if this container was shared between threads?


If there's any chance of asynchronous interruptions then obviously the
background threads must not modify shared containers; they should
modify private copies which are then copied back to the main thread
when calculation is complete and known to have succeeded.

Alternatively, they could invoke back to the main thread for making
changes. Usually you can't just secretly modify shared data in
another thread anyway since some part of the main thread needs to know
about the change, update related data or the UI or whatever.


Who's talking about secretly? I'm talking about editing shared state
protected by a lock or any other synchronization mechanism. I know pretty
well what shared state means, don't worry ;-)
(As an aside, this is also one reason why I believe the old
Synchronized wrappers for the non-generic collections were a horrible,
horrible idea. They might trick people into doing exactly what you
propose here, assuming that everything is "thread-safe" because the
documentation says so...)
See above, I did not suggest anything like that.
No it isn't, if the abort occurs after memory allocation but before ptr
assignment, you'll end with ptr still being "null" when your finally runs,
bummer memory leak. This isn't an issue when you unload the AD, but what
if
you continue to execute code inside this domain?


Okay, that's a really good point. Hmm... I suppose the only way to
avoid this is to not allocate any critical resources within code
blocks where Thread.Abort is possible.


That would mean your code can't safely call into the FCL, because you don't
(and shouldn't) know exactly what's going on in there. For instance you
can't call a method that PInvoke's an API while it's argument marshaling
requires allocation of a memory block like it's the case when marshaling
Strings to/from Ansi (and don't get me started discussing COM interop
scenario's).

You could always use Monitor locks to protect such blocks, though; How would a Monitor be of any help here?

or allocate resources in the main thread before handing the references over to the worker thread.
That would mean you start coding specifically to handle thread abort not
induced by AD unloads, but this would put severe restrictions on what you
can possibly do in your thread functions.

The possibility of a ThreadAbortException interrupting a reference
assignment is really aggravating, though. I'd say that calls for some
kind of IL primitive that prevents a statement sequence from being
interrupted. That would mean that resource acquisitions and assignments should be made
atomic.
This is taken care of in V2 by means of Constrained Execution Regions
(CER's), but they are highly restrictive and have a serious performance
impact.

Since the Framework team already figured out how to protect static ctors and catch/finally blocks that should be possible.
The figured out to protect cctor's because this is (was) a serious issue in
V1.x when unloading an AD with possibly corrupted statics.

No, for me rule to remember is "Never initiate asynchronous thread aborts
in
Framework code, unless it's part of an AD unload", there are more secure
alternatives to stop a thread from making progress.


But not asynchronously, which is the point.


True, but with a guarantee that I don't corrupt AD state, so I can safely
restart the task without the need to recycle the AD.

With any alternative method, the thread that is to be stopped must actively check for some
kind of signal. That may be very difficult to implement if your
thread is doing some complex and lengthy computation.
--


It's much easier to do than to write paranoid code necessary to deal with
thread aborts like you are suggesting. Anyway, this was my last reply as
this is way OT for this NG.

Willy.
Nov 17 '05 #15

P: n/a
> However , you still have to consider state acquired outside a try block,
where a thread abort can occur between any machine instruction.
<snip> But consider this ...
using(SomeExpensiveResource res = new(....))
{
...
}
a thread abort can be raised after the constructor invocation but before
the assignment of res, as this abort occurs outside the try block, finally
never runs and Dispose is never called. (Note that res == null, so Dispose
could never be called anyway).


This is slightly off topic but related to the race condition you mention
here....

If a thread abort can occur between two machine instructions such as in your
example, between the constructor invocation and the assignment of the
reference to a local variable, then could the thread also be suspended by
the GC between those two instructions? If this race is not prevented by the
runtime (e.g. all threads must rendevous at a known "safe" point before the
GC can suspend them) then the GC might consider the object that was just
created to be unreachable and thus reclaim it before the assignment to the
variable could be made.

If so, then I would consider it likely that on some heavily loaded
mulithreaded applications a memory allocation request on one thread could
cause a GC cycle to occur that would occasionally suspend another thread and
on some rare occasions the new object would be GC'd before it could be
assigned to a variable and used.

In a general sense I would think this race is inherent in that an object is
new'd by the runtime and its lifetime must be tracked by the GC after the
call to new the object is completed and before the reference is returned to
the caller.

Do you know how this type of race condition is dealt with?
Nov 17 '05 #16

P: n/a

"David Levine" <no******************@wi.rr.com> wrote in message
news:%2****************@tk2msftngp13.phx.gbl...
However , you still have to consider state acquired outside a try block,
where a thread abort can occur between any machine instruction.
<snip>

But consider this ...
using(SomeExpensiveResource res = new(....))
{
...
}
a thread abort can be raised after the constructor invocation but before
the assignment of res, as this abort occurs outside the try block,
finally never runs and Dispose is never called. (Note that res == null,
so Dispose could never be called anyway).


This is slightly off topic but related to the race condition you mention
here....

If a thread abort can occur between two machine instructions such as in
your example, between the constructor invocation and the assignment of the
reference to a local variable, then could the thread also be suspended by
the GC between those two instructions? If this race is not prevented by
the runtime (e.g. all threads must rendevous at a known "safe" point
before the GC can suspend them) then the GC might consider the object that
was just created to be unreachable and thus reclaim it before the
assignment to the variable could be made.

If so, then I would consider it likely that on some heavily loaded
mulithreaded applications a memory allocation request on one thread could
cause a GC cycle to occur that would occasionally suspend another thread
and on some rare occasions the new object would be GC'd before it could be
assigned to a variable and used.

In a general sense I would think this race is inherent in that an object
is new'd by the runtime and its lifetime must be tracked by the GC after
the call to new the object is completed and before the reference is
returned to the caller.

Do you know how this type of race condition is dealt with?

I know how it's dealt with in v1.1, but I'm not sure how it's done in V2.0.
Objects can only be allocated after a "PreemptiveGC" is disabled for the
current thread, that means that the thread cannot be hijacked for GC during
allocation, this is taken care of by the EE.
In V1.1 object allocations are serialized by an allocation lock (actually a
flag) , when the lock is taken by an other request, it spinlocks. The lock
is released before the object gets registered for finalization so it's only
taken for a brief period and it will never provoke or allow a (Cooperative)
GC while the lock is held.
Note also that it's not necessary for the object reference to be present as
a value on the stack, the object allocator returns a reference to EAX which
is a valid root for the GC to scan.

Willy.


Nov 17 '05 #17

P: n/a
>
I know how it's dealt with in v1.1, but I'm not sure how it's done in
V2.0.
Objects can only be allocated after a "PreemptiveGC" is disabled for the
current thread, that means that the thread cannot be hijacked for GC
during allocation, this is taken care of by the EE.
In V1.1 object allocations are serialized by an allocation lock (actually
a flag) , when the lock is taken by an other request, it spinlocks. The
lock is released before the object gets registered for finalization so
it's only taken for a brief period and it will never provoke or allow a
(Cooperative) GC while the lock is held.
Note also that it's not necessary for the object reference to be present
as a value on the stack, the object allocator returns a reference to EAX
which is a valid root for the GC to scan.

Willy.


Thanks. I'm not quite sure how the operation of the allocation flag effects
this race condition but disabling a preemptive GC on the requesting thread
and returning the reference in EAX explains most of what I was wondering
about.

Nov 17 '05 #18

P: n/a
>
I know how it's dealt with in v1.1, but I'm not sure how it's done in
V2.0.
Objects can only be allocated after a "PreemptiveGC" is disabled for the
current thread, that means that the thread cannot be hijacked for GC
during allocation, this is taken care of by the EE.
In V1.1 object allocations are serialized by an allocation lock (actually
a flag) , when the lock is taken by an other request, it spinlocks. The
lock is released before the object gets registered for finalization so
it's only taken for a brief period and it will never provoke or allow a
(Cooperative) GC while the lock is held.
Note also that it's not necessary for the object reference to be present
as a value on the stack, the object allocator returns a reference to EAX
which is a valid root for the GC to scan.

Willy.


Thanks. I'm not quite sure how the operation of the allocation flag effects
this race condition but disabling a preemptive GC on the requesting thread
and returning the reference in EAX explains most of what I was wondering
about.

Nov 17 '05 #19

This discussion thread is closed

Replies have been disabled for this discussion.