Re: Exceptions Thrown in Background Threads

From: David Levine (noSpamdlevineNNTP2_at_wi.rr.com)
Date: 09/07/04


Date: Mon, 6 Sep 2004 22:51:52 -0500


>
> 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.

> > 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.
>
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.

> > 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.
>

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.

> > 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":
>

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.

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

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/default.asp?url=/library/en-us/cpguide/html/cpconhandlingraisingexceptionsinxmlwebservices.asp

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/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.

> > 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.

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.



Relevant Pages

  • Re: Exception management question...
    ... There is code in my app that follows this general pattern: ... This allows an exception to be thrown with the next line of code attempts to ... >> to propagate up to a global exception handler which logs the exception ... > has determined that the app should terminate the UE handler has no means ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Need crash dump from Managed app
    ... is to create a TextWriterTraceListener and start logging every P/Invoke call ... The exception handler was never executed. ... I have a test C++ app with the following startup code: ...
    (microsoft.public.pocketpc.developer)
  • Re: Logging (exceptions etc)
    ... So basically I'm thinking I need to include a UE handler as a last resort, ... I've become annoyed with the add-in dying (and taking the main app with it) ... > exception to be unhandled, especially if you are writing an add-in. ... > unhandled exception event will be sent and the exception will be ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Try Finally...
    ... Now we can protect every more or less specialized action ... an error indication (exception or error code) has to be ... an according exception handler can be inserted into the code. ... resources, as they are related to specific actions. ...
    (comp.lang.pascal.delphi.misc)
  • WinForms bug? ThreadException not invoked on Exceptions in system code pre-processing the messag
    ... Message Queue and invoking the appropriate handler. ... if an Exception is raised during the PRE-PROCESSING of a Windows ... before this point in the app... ...
    (microsoft.public.dotnet.framework.windowsforms)

Loading