Exceptions Thrown in Background Threads

  • Thread starter Thread starter Cool Guy
  • Start date Start date
C

Cool Guy

Consider:

[begin code]

void Start()
{
if (!TryToDoSomething())
ShowErrorMessage();
}

void TryToDoSomething()
{
try
{
Thread thread = new Thread(new ThreadStart(DoSomething);
thread.IsBackground = true;
thread.Start();

return true;
}
catch (SomeException)
{
return false;
}
}

void DoSomething()
{
DoSomethingWhichMightThrowASomeException();
}

[end code]

Trying to catch the SomeException in TryToDoSomething doesn't seem to work,
presumably because the exception is thrown in a separate thread. Is this
correct?

If so, what's the best was of dealing with this exception so that I can
call ShowErrorMessage in the main thread when it's thrown?
 
Trying to catch the SomeException in TryToDoSomething doesn't seem to work,
presumably because the exception is thrown in a separate thread. Is this
correct?

That is correct. You must catch the exception on which it is thrown.
If so, what's the best was of dealing with this exception so that I can
call ShowErrorMessage in the main thread when it's thrown?

Here's a way to do that for purposes of illustration; I would not actually
do it this way.

private Exception theException = null;
void MainEntryPointToTryToDoSomething()
{
Thread thread = new Thread(new ThreadStart(DoSomething);
thread.IsBackground = true;
thread.Start();
thread.Join(); // wait until thread terminates
if ( theException != null )
ShowErrorMessage(theException);
}

void DoSomething()
{
try
{
DoSomethingWhichMightThrowAnException();
|}
catch(Exception ex)
{
theException = ex; // save it
}
}


Basically the idea is the save the exception object so that it is available
to the thread which will display the error message. This example used a
global variable, theException. A better way to handle this is to use the
Async pattern as used by the BCL
Note also that you must use thread.Join, or some other synchronization
primitive such as an async callback, to correctly rendevous when the thread
is done.
 
David said:
Here's a way to do that for purposes of illustration; I would not actually
do it this way.

I like the simplicity of this solution. Why wouldn't you do it this way --
is it a bad idea?
A better way to handle this is to use the
Async pattern as used by the BCL

Hmm... I've never heard of this. Google didn't turn up anything, either.

Thanks for the help.
 
Cool said:
Consider:

[begin code]

void Start()
{
if (!TryToDoSomething())
ShowErrorMessage();
}

void TryToDoSomething()
{
try
{
Thread thread = new Thread(new ThreadStart(DoSomething);
thread.IsBackground = true;
thread.Start();

return true;
}
catch (SomeException)
{
return false;
}
}

void DoSomething()
{
DoSomethingWhichMightThrowASomeException();
}

[end code]

Trying to catch the SomeException in TryToDoSomething doesn't seem to
work, presumably because the exception is thrown in a separate
thread. Is this correct?
Yes.

If so, what's the best was of dealing with this exception so that I
can call ShowErrorMessage in the main thread when it's thrown?

Use events. Assume you have a class "Main", which controls your
application's main thread (e.g. a Windows Form), and a class "Worker" that
performs lengthy operations on a separate thread to avoid blocking Main's
thread. If Worker exposes an event "Error", which is triggered whenever an
exception needs to be communicated to Worker's owner, Main can simply
subscribe to the Error event through standard event handling:

/* Note that ErrorEventArgs and ErrorEventHandler do already exist in
System.IO */

class Main {
private Worker worker;

public Main() {
this.worker = new Worker();
this.worker.Error += new ErrorEventHandler(this.Worker_Error);
}

private void Worker_Error(object sender, ErrorEventArgs e) {
// CAVEAT: If this is a WinForm class, first marshal the call
// back to the UI thread!
// Do something... display message, log to file, etc.
}
}

class Worker {
public event ErrorEventHandler Error;

public void Work() {
// kick off DoWork() in another thread
}

protected virtual void OnError(ErrorEventArgs e) {
ErrorEventHandler handler = Error;
if (handler != null) {
handler(this, e);
}
}

private void DoWork() {
try {
// heavy stuff...
}
catch (Exception ex) {
OnError(new ErrorEventArgs(ex));
}
}
}

Of course this approach allows to to communicate anything back to Main,
including completion results of Work(). Plus, it nicely abstracts from how
Work() actually makes DoWork() run on another thread... whether it uses its
own managed thread, an async delegate, whatever -- the approach is the same.

Note the CAVEAT comment in Worker_Error: If you use this approach in Windows
Forms apps, you *must* protect all such callbacks by assuring each call is
marshalled back to the UI thread if necessary, using Control.InvokeRequired
and Control.Invoke().

Cheers,
 
Cool Guy said:
I like the simplicity of this solution. Why wouldn't you do it this
way --
is it a bad idea?


Hmm... I've never heard of this. Google didn't turn up anything, either.

Here is a sample running a thread proc on a threapool thread using async
delegates. Check msdn for details.

using System;
using System.Threading;
// Async delegate
public delegate void Proc(StateObject o);

public class Forked {
static void Worker(StateObject o) {
Console.WriteLine("Thread {0}, executing Worker, " + "is {1}from the
thread pool.",Thread.CurrentThread.GetHashCode(),
Thread.CurrentThread.IsThreadPoolThread ? "" : "not ");
int r;
int y = 0;
r = 10/y; // Do something really nasty
}

public static void Main() {
Proc proc = new Proc(Worker);
// Do some work using an async. delegate (running on a threadpool thread)
IAsyncResult call = proc.BeginInvoke(null, null, null);
// Do some other work .....
Console.WriteLine("Primary thread {0}",
Thread.CurrentThread.GetHashCode());
try {
//Asynch. Rendez-vous. Just call EndInvoke at some point within a try
block and you'll see the exception.
proc.EndInvoke(call);
}
catch (Exception ex) {
Console.WriteLine("{0}", ex.Message);
}
}
}


Willy.
 
On second thoughts, this wouldn't work in my situation, because I need to
leave MainEntryPointToTryToDoSomething after the call to Thread.Start if an
exception isn't thrown.

At current, MainEntryPointToTryToDoSomething waits until the thread is
finished even if an exception isn't thrown.

I guess I'll have to use events like Joerg suggested. Or is this possible
with some other method?
 
Hi Cool Guy,

You can set up a global exception handler, similar to this:

using System;
using System.Threading;

public class Test
{
public void GlobalExceptionHandler(object sender,
UnhandledExceptionEventArgs e)
{
Console.WriteLine(e.ExceptionObject.ToString());
}

public static void Main()
{
Test t = new Test();
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(t.GlobalExceptionHandler);
t.Start();
}
void Start()
{
if (!TryToDoSomething())
Console.WriteLine("!TryToDoSomething()");
}

bool TryToDoSomething()
{
try
{
Thread thread = new Thread(new ThreadStart(DoSomething));
thread.IsBackground = true;
thread.Start();

thread.Join();

return true;
}
catch (ApplicationException)
{
return false;
}
}

void DoSomething()
{
throw new ApplicationException("Test Exception");
}
}

Joe
 
I would recommend not doing it this way. All the other mechanisms provide
the opportunity to respond to the exception when it occurs; or if the
handler is deferred, then another opportunity to handle it occurs when
EndInvoke is called. Also, the timing between catch handlers and finally
blocks are run is well defined.

One problem with using the unhandled exception handler is that the
notification occurs after the ability to respond to the exception has past.
If the exception were to occur on the main thread or a thread that
originated in unmanaged code, then in the 1.1 runtime the application will
terminate immediately after the unhandled event it delivered. In future
versions of the runtime the app may terminate even if the exception occurred
on a worker thread (it may even be a configurable policy decision of the
app). Regardless, I would not rely on this working consistently across
multiple versions of the runtime.

More subtle issues may arise when there are timing constraints between when
an exception occurs, when it is handled, and when finally blocks are run.
Handling an exception from an unhandled exception handler adds to the number
of code paths and changes the timing of when the event is delivered and when
finally blocks are run. This may not be a problem, but then again...


Joe Mayo said:
Hi Cool Guy,

You can set up a global exception handler, similar to this:

using System;
using System.Threading;

public class Test
{
public void GlobalExceptionHandler(object sender,
UnhandledExceptionEventArgs e)
{
Console.WriteLine(e.ExceptionObject.ToString());
}

public static void Main()
{
Test t = new Test();
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(t.GlobalExceptionHandler);
t.Start();
}
void Start()
{
if (!TryToDoSomething())
Console.WriteLine("!TryToDoSomething()");
}

bool TryToDoSomething()
{
try
{
Thread thread = new Thread(new ThreadStart(DoSomething));
thread.IsBackground = true;
thread.Start();

thread.Join();

return true;
}
catch (ApplicationException)
{
return false;
}
}

void DoSomething()
{
throw new ApplicationException("Test Exception");
}
}

Joe
--
Joe Mayo, Author/Instructor
Need C#/.NET training?
visit www.mayosoftware.com
C# Tutorial - www.csharp-station.com



Cool Guy said:
Consider:

[begin code]

void Start()
{
if (!TryToDoSomething())
ShowErrorMessage();
}

void TryToDoSomething()
{
try
{
Thread thread = new Thread(new ThreadStart(DoSomething);
thread.IsBackground = true;
thread.Start();

return true;
}
catch (SomeException)
{
return false;
}
}

void DoSomething()
{
DoSomethingWhichMightThrowASomeException();
}

[end code]

Trying to catch the SomeException in TryToDoSomething doesn't seem to work,
presumably because the exception is thrown in a separate thread. Is this
correct?

If so, what's the best was of dealing with this exception so that I can
call ShowErrorMessage in the main thread when it's thrown?
 
Thanks, that's exactly what I had in mind.

Willy Denoyette said:
Here is a sample running a thread proc on a threapool thread using async
delegates. Check msdn for details.

using System;
using System.Threading;
// Async delegate
public delegate void Proc(StateObject o);

public class Forked {
static void Worker(StateObject o) {
Console.WriteLine("Thread {0}, executing Worker, " + "is {1}from the
thread pool.",Thread.CurrentThread.GetHashCode(),
Thread.CurrentThread.IsThreadPoolThread ? "" : "not ");
int r;
int y = 0;
r = 10/y; // Do something really nasty
}

public static void Main() {
Proc proc = new Proc(Worker);
// Do some work using an async. delegate (running on a threadpool thread)
IAsyncResult call = proc.BeginInvoke(null, null, null);
// Do some other work .....
Console.WriteLine("Primary thread {0}",
Thread.CurrentThread.GetHashCode());
try {
//Asynch. Rendez-vous. Just call EndInvoke at some point within a try
block and you'll see the exception.
proc.EndInvoke(call);
}
catch (Exception ex) {
Console.WriteLine("{0}", ex.Message);
}
}
}


Willy.
 
David Levine said:
I would recommend not doing it this way. All the other mechanisms provide
the opportunity to respond to the exception when it occurs; or if the
handler is deferred, then another opportunity to handle it occurs when
EndInvoke is called. Also, the timing between catch handlers and finally
blocks are run is well defined.

It appears that an asynchronous delegate was an acceptable solution for OP,
but this isn't always the case. There are times when people need to use a
normal thread, rather than an asynchronous delegate. A specific exception
may be handled on the thread where code can be wrapped in a try/catch block.
However, it isn't practical to write catch blocks for every possible
exception that can be raised. The global exeption handler can serve as a
backup mechanism to keep your program from crashing because of unhandled
exceptions. The decision on whether to catch System.Exception may or may
not have anything to do with timing between catch and finally blocks,
depending on the application.
One problem with using the unhandled exception handler is that the
notification occurs after the ability to respond to the exception has
past.

I think it depends on the application as to whether this matters or not.
If the exception were to occur on the main thread or a thread that
originated in unmanaged code, then in the 1.1 runtime the application will
terminate immediately after the unhandled event it delivered.

Sure, global exeption handlers are for managed code. The fact that some
unmanaged code might crash the CLR still doesn't convince me that I
shouldn't use a global exception handler.
In future
versions of the runtime the app may terminate even if the exception occurred
on a worker thread (it may even be a configurable policy decision of the
app). Regardless, I would not rely on this working consistently across
multiple versions of the runtime.

Why would you not rely on this working consistently across multiple versions
of the runtime? Microsoft explains how this is done through their
architectural guidance document "Exception Management in .NET":

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/exceptdotnet.asp

I'm open minded enough to hear new ideas and if you have information that
would change my mind, then I'm interested in hearing it.
More subtle issues may arise when there are timing constraints between when
an exception occurs, when it is handled, and when finally blocks are run.
Handling an exception from an unhandled exception handler adds to the number
of code paths and changes the timing of when the event is delivered and when
finally blocks are run. This may not be a problem, but then again...

Right. It could be a problem, i.e. in cases where you caught a specific
exception and want capture some information before disposing a resource.
However, I don't see that as a reason not to have a global exception
handler.
Joe Mayo said:
Hi Cool Guy,

You can set up a global exception handler, similar to this:

using System;
using System.Threading;

public class Test
{
public void GlobalExceptionHandler(object sender,
UnhandledExceptionEventArgs e)
{
Console.WriteLine(e.ExceptionObject.ToString());
}

public static void Main()
{
Test t = new Test();
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(t.GlobalExceptionHandler);
t.Start();
}
void Start()
{
if (!TryToDoSomething())
Console.WriteLine("!TryToDoSomething()");
}

bool TryToDoSomething()
{
try
{
Thread thread = new Thread(new ThreadStart(DoSomething));
thread.IsBackground = true;
thread.Start();

thread.Join();

return true;
}
catch (ApplicationException)
{
return false;
}
}

void DoSomething()
{
throw new ApplicationException("Test Exception");
}
}

Joe
--
Joe Mayo, Author/Instructor
Need C#/.NET training?
visit www.mayosoftware.com
C# Tutorial - www.csharp-station.com



Cool Guy said:
Consider:

[begin code]

void Start()
{
if (!TryToDoSomething())
ShowErrorMessage();
}

void TryToDoSomething()
{
try
{
Thread thread = new Thread(new ThreadStart(DoSomething);
thread.IsBackground = true;
thread.Start();

return true;
}
catch (SomeException)
{
return false;
}
}

void DoSomething()
{
DoSomethingWhichMightThrowASomeException();
}

[end code]

Trying to catch the SomeException in TryToDoSomething doesn't seem to work,
presumably because the exception is thrown in a separate thread. Is this
correct?

If so, what's the best was of dealing with this exception so that I can
call ShowErrorMessage in the main thread when it's thrown?
 
It appears that an asynchronous delegate was an acceptable solution for OP,
but this isn't always the case. There are times when people need to use a
normal thread, rather than an asynchronous delegate.

What do you mean by normal? Do you mean to distinguish between a threadpool
thread and a manually created thread?
A specific exception
may be handled on the thread where code can be wrapped in a try/catch block.
However, it isn't practical to write catch blocks for every possible
exception that can be raised.

The only time where it is not practical is when the exception actually
occurs in code written by 3rd parties over which you have no control and on
threads which are created internally by the 3rd party code. In this case,
the reason why you cannot wrap it in a try-catch is because it is not
possible, not because it is not practical. In all other cases, if the
exception occurs in a thread proc written by yourself you can wrap it in a
try-catch.

You may be thinking that you do not want to catch all exception types within
the scope of a particular catch block. I partially agree with that, but that
is still not the same thing as wrapping all your execution threads in a
try-catch block. A particular subsystem may catch some exceptions but not
all, and that is fine, but the code that invokes it should wrap it in its
own backstop try-catch handler - the buck has to stop somewhere, and it
ought not to be in a UE handler.

I also am unconvinced that not all exception types should be caught - I
prefer to catch-wrap-throw to add context to the exception error message.
The extra performance hit is usually less important then the additional
error information available to users/tech support/developers.

The global exeption handler can serve as a
backup mechanism to keep your program from crashing because of unhandled
exceptions.

This is an incorrect statement. You will definitely NOT keep a program from
terminating. One of the fields (IsTerminating) in the unhandled exception
event argument indicates whether or not the runtime is terminating as a
result of the unhandled exception. This is a readonly field - if it is set
to true then the application will terminate immediately after the unhandled
exception handler has run to completion. The app has no direct control over
this value.
The decision on whether to catch System.Exception may or may
not have anything to do with timing between catch and finally blocks,
depending on the application.

I do not follow the logic in this statement. The specific exception type
caught has nothing to do with the timing between the catch-finally blocks.

past.

I think it depends on the application as to whether this matters or not.
True, but the difference is whether or not the runtime will terminate the
app immediately thereafter - the app has no control over this. Currently the
only way to influence this is by the thread the UE occurs on.

Sure, global exeption handlers are for managed code. The fact that some
unmanaged code might crash the CLR still doesn't convince me that I
shouldn't use a global exception handler.

Threads can originate in unmanage code and make calls that wind up in
managed code (e.g. CCW). If managed code makes a call to unmanaged code and
that code throws an exception, or if it returns an error that the runtime
converts to an exception, then the runtime will propagate that exception
back up the callstack to the managed thread. An unhandled exception handler
is for all exceptions reflected into the managed environment, regardless of
where it originated.

While it is true that a call into unmanaged code can crash the app, it is
not necessarily because of an unhandled exception on a managed thread -
unmanaged code can directly call TerminateProcess and the runtime cannot
guard against that. It could also launch another unmanaged thread, have an
unhandled exception on that thread, and the win32 subsystem can crash the
app. Unmanaged code is code in the wild.

If the exception occurs on the execution thread that calls into unmanaged
code, then if that code throws an exception it can be caught the same as any
other exception.
Why would you not rely on this working consistently across multiple versions
of the runtime? Microsoft explains how this is done through their
architectural guidance document "Exception Management in .NET":

There are inconsistencies and weaknesses in how exception handling is
implemented, and the behavior will probably change. For one thing, you can
only successfully subscribe to the unhandled exception event in the default
appdomain. You can subscribe to it in other appdomains but the handler for
it will never be called, and the subscription attempt itself does not
generate an error to indicate an error. For another, the decision of whether
to terminate the app is based algorithms that are questionable (e.g. why
should it matter which thread the UE occurred on?), and even worse, make it
impossible for an app to fully control an execution environment.

The decision to terminate an app or not should be a policy decision by the
controlling app, and the system should provide reasonable default backstop
behavior. There currently is no way for an app, such as a managed host
setting up a secure execution environment, to set this policy - there ought
to be.

The management guide also is misleading in its description of how a UE is
handled by the runtime. I think it is good guide but not the last word on
the subject. The links I provided go into detail on the mechanics of
exception handling in .net.


I'm very familiar with that link you provided and the information it
provides is incomplete.
Here are a few links you should read...

http://blogs.msdn.com/cbrumme/archive/2003/04/15/51345.aspx
http://blogs.msdn.com/cbrumme/archive/2003/10/01/51524.aspx
http://www.microsoft.com/msj/0197/Exception/Exception.aspx
http://msdn.microsoft.com/library/d...handlingraisingexceptionsinxmlwebservices.asp

http://msdn.microsoft.com/library/d...ml/vbtskhandlingexceptionsinyourcomponent.asp


I'm open minded enough to hear new ideas and if you have information that
would change my mind, then I'm interested in hearing it.
For one, there is a big difference between what are called unhandled
exception handlers and the "raw" unhandled exception handler as implemented
by the runtime. The winform UE handler (and I believe the ASP UE handler as
well) do not appear to actually provide access to the low-level UE. From the
testing I have done the Winform UE seems to wrap the winform itself in a
try-catch (and only on the main thread), and if your own app does not catch
the exception it will catch it and deliver the UE itself to any subscribed
listeners - this prevents the UE from crashing the app because from the
runtime's perspective the exception was handled. If none are subscribed the
exception is allowed to propagate and is treated as a normal UE (I believe
it propagates without actually being caught and rethrown - I suspect it
makes the decision in an exception filter).

The difference between the two can be observed by examining the timing
between when the UE is delivered to subscribed event handlers and when
finally blocks run. The low-level UE event will be delivered after the
runtime has performed the 1st pass of searching for a suitable catch handler
and before finally blocks are run. If none is found it fires the UE event
and then goes back and on the 2nd pass it runs all finally blocks; the
sequence is to 1st search for a catch handler, deliver the UE and then 2nd
run the finally blocks. For winform apps that subscribed to the
Application.ThreadException event, this is delivered after all finally
blocks have run, which is what the behavior would be if it caught the
exception itself and then delivered the event. The sequence here is to 1st
search for a catch handler, then on the 2nd pass to run the finally blocks,
and then to eventually deliver the UE event.

I haven't actually tested the asp.net behavior but I believe it is very
similar to what I've described for the winform. The reason why the app
doesn't crash when subscribed to either is that the runtime library is
handling the exception on your behalf.

Now, if you don't care about the difference that is fine, but one should at
least know that there is a difference.

As far as I can tell there are 3 different UE mechanisms, 1 in the runtime
and 2 in the BCL...

AppDomain.UnhandledException (runtime)
Application.ThreadException (WinForms BCL)
Page.Error and Application_Error (ASP .NET BCL)

The 1st is the runtime's notion of a UE handler.

I believe the other two are provided by the BCL and are layers on top of the
runtime's standard exception handling. If you get a winform or asp.net UE
event then the runtime itself does not see it as a UE. Again, this is based
on my observation - I do not have the actual source code to see how it was
actually done. I suspect those lib's actually use an exception filter to
determine whether to catch the exception and generate the UE event or let it
propagate unhandled.

Right. It could be a problem, i.e. in cases where you caught a specific
exception and want capture some information before disposing a resource.

That is correct. And there is a difference in the timing when a finally
block is run and the UE is delivered depending on whether it is an Appdomain
UE or the Winform or ASP UE. In most cases it does not matter, but sometimes
it might.
However, I don't see that as a reason not to have a global exception
handler.

Then I suppose we shall have to agree to disagree. I believe a UE should be
used for logging/trouble-shooting, etc, but it does not prevent an app from
terminating. For actually dealing with exceptions I believe that
try-catch-finally constructs should always be used - IMO doing other then
this encourages sloppy programming habits. For my own code I always treat a
UE as a programming error on my part. OP can do as they please.
 
Back
Top