1

I know it is not good practice to catch System.Exception unless on the top level of an application. What about a thread? Is it okay to catch System.Exception on the top level of the thread?

Update: The thread is a long running thread that should only be terminated when the application stops. So in order to make sure that the application does not crash I simply catch System.Exception and log the error. Everything is recreated.

        while (Terminate == false)
        {
            var discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());

            try
            {
                var criteria = new FindCriteria(typeof(T));
                criteria.Scopes.Add(new Uri(Scope));
                var discovered = discoveryClient.Find(criteria);
                discoveryClient.Close();
                discoveryClient = null;

                // do something with the endpoints
            }
            catch (OutOfMemoryException e)
            {
                m_Logger.LogException(e, "Exception when trying to discover clients (Contract: {0})", typeof(T).Name);
                throw;
            }
            catch (Exception e)
            {
                m_Logger.LogException(e, "Exception when trying to discover clients (Contract: {0})", typeof(T).Name);

                if (discoveryClient != null)
                    (discoveryClient as IDisposable).Dispose();
            }

        }
Michael
  • 1,081
  • 1
  • 12
  • 27
  • It's not good practice to catch `System.Exception` at the top level of an application, either ([more information here](http://stackoverflow.com/questions/4827628/main-method-code-entirely-inside-try-catch-is-it-bad-practice/4827646#4827646)). Why are you trying to do this at all? – Cody Gray - on strike Apr 04 '11 at 12:11

5 Answers5

3

It depends on what the thread is doing and the context of the thread in your application. Generally speaking, you should follow the golden rule of thumb: do not catch an exception unless you know how to handle it. (I am simplifying of course, but it's a rule of thumb).

Since we are talking about System.Exception and not some subclass, I assume that you would not in fact know how to handle the exception. Logging the error and letting the application terminate (the only legitimate reason to catch an exception you can't handle) can be done without catching the exception from within the thread that raised it, so the short answer is no, it's no OK.

If I remember correctly .NET 1 actually caught and swallowed all exceptions raised on background threads. This led to so many problems in badly written programs that MS changed the behavior in .NET 2 to let the exceptions crash the app -- and you can imagine they had very good reason to make such a breaking change.

Update regarding BackgroundWorker:

Please do not mistake the usage model of BackgroundWorker for "swallowing System.Exception is OK". Here's what the docs for BackgroundWorker.RunWorkerCompleted say:

Your RunWorkerCompleted event handler should always check the AsyncCompletedEventArgs.Error and AsyncCompletedEventArgs.Cancelled properties before accessing the RunWorkerCompletedEventArgs.Result property. If an exception was raised or if the operation was canceled, accessing the RunWorkerCompletedEventArgs.Result property raises an exception.

Choosing to disregard this suggestion or ignoring the return value on purpose (otherwise an exception will still be thrown!) is, simply put, bad programming practice.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • Agree. Catching just for the sake of not letting the application crash causes that it seems that nothing happens, but in fact there was an important failure. At least show an error message, log all the information possible anc shutdown the application. Otherwise you are just hiding an error. – Haplo Apr 04 '11 at 12:23
  • @Haplo - Jon says it's not OK and you agree but then you suggest showing an error message, logging and shutting down, which requires that it be done. ... ? – Kieren Johnstone Apr 04 '11 at 12:28
  • @Kieren: No, none of that requires that you catch the exception. Jon suggests handling the `AppDomain.UnhandledException` event, which is the correct way to do this. I can only assume that's what @Haplo is referring to. – Cody Gray - on strike Apr 04 '11 at 12:30
  • -1. I completely disagree, and so do the designers of System.ComponentModel.BackgroundWorker, which very sensibly catches exceptions at the top level of the internal WorkerThreadStart method. Of course catching it doesn't necessarily mean silently swallowing it... – Joe Apr 04 '11 at 12:33
  • @kieren-johnstone I mean that doing what I often see, catch-log and continue running the app it's not a good practice. But also it's not good that users are working and all of a sudden the application crashes. So instead letting the application crash, put a global try-catch, log all the info you can, show a message in the style of 'critical error.Application cannot continue' and close it. The effect is the same as not caching, but is much user friendly... You could even force a memory dump with DrWatson (I did that some years ago) – Haplo Apr 04 '11 at 12:33
  • Ah that subtle link - I see, `AppDomain.UnhandledException` is a good alternative that I didn't think of. – Kieren Johnstone Apr 04 '11 at 12:34
  • Yes, that's exactly what Microsoft Office applications do. "A critical error occurred. The application cannot continue." I think that qualifies as a "real" app. The people who disagree here are talking about *background* worker threads, which isn't necessarily the same thing. If it's *impossible* for an exception in that thread to corrupt your application's state, then obviously you don't have to crash. But if there's even the slightest possibility, crashing is the right thing to do. Again, no one says you shouldn't catch exceptions. The problem is catching the base class `System.Exception`. – Cody Gray - on strike Apr 04 '11 at 12:36
  • @Kieren - Agree, I didn't think of it :) – Haplo Apr 04 '11 at 12:37
  • 1
    @Joe: Please read the update and tell me if you still think the designers of `BackgroundWorker` disagree. – Jon Apr 04 '11 at 12:49
  • @Jon, I do still think so, as BackgroundWorker does catch the exception in the Thread. But from your update, I see you agree with me that "...Of course catching it doesn't necessarily mean silently swallowing it... ". BTW ASP.NET is another Framework example where exceptions are caught - again not silently swallowed but used to generate an HTTP error response. – Joe Apr 04 '11 at 13:10
  • @Joe: An HTTP error response, in the web server context, is the same as a desktop application crashing. So we don't disagree indeed. – Jon Apr 04 '11 at 13:37
  • "An HTTP error response, in the web server context, is the same as a desktop application crashing". It's quite different. For example, the Session is maintained server-side, and the client can retry his last request. Some people (e.g. @Stuart's answer) give dark warnings about the possibility of data corruption if exceptions are caught, which in my view is FUD. If an ASP.NET server application can safely continue running after catching an exception, I'm sure most desktop applications can too. – Joe Apr 04 '11 at 13:59
  • @Joe: The fact that the *server process itself* does not crash is a deliberate design decision that makes much sense *in this specific case*. If you are writing an application whose purpose is to run third-party code and you need to be stable in the presence of errors in that code, then sure this is the way to go. **But the OP's question is much broader in scope.** – Jon Apr 04 '11 at 14:06
  • 1
    @Joe: Also, the session being maintained etc is totally irrelevant. If Word crashes, there's code in it that allows you to continue working without losing your unsaved changes. Maintaining state and crashing are orthogonal. – Jon Apr 04 '11 at 14:08
  • @Jon: not sure I understand how your Word example (persist snapshots of state to disk for recovery after crash & restart) relates to the fact that the ASP.NET application domain catches exceptions and keeps running. I'm not sure why, but this seems to be a contentious topic. I don't thing we really disagree, I am only objecting to the contention that it is *always* wrong to catch exceptions at the top level. – Joe Apr 05 '11 at 07:33
  • @Joe: We probably don't disagree. Keep in mind that I don't said it's *always* wrong. The answer starts with "it depends" and takes two short paragraphs to reach the "no" conclusion. My objection is to the "yeah sure go ahead" mindset without provisions. – Jon Apr 05 '11 at 08:28
2

Yes - it's an excellent idea :)

Umm, I can't see why people are suggesting it's not a good idea to catch top-level exceptions. Seriously, you don't catch them?

From an actual day-to-day development standpoint, if your background thread has a top-level exception, you want to know about it. You don't want the app to crash, the default behaviour - users don't like that, surprisingly. This is one of the few places you definitely want to catch exceptions and log/recover.

Kieren Johnstone
  • 41,277
  • 16
  • 94
  • 144
  • I suppose this is intended to be ironic? Unfortunately, that's not entirely clear. Either way, I suggest editing your answer to provide more information. – Cody Gray - on strike Apr 04 '11 at 12:16
  • I can't think what more information is needed. Is it a good idea? Yes. Is it OK? Yes... – Kieren Johnstone Apr 04 '11 at 12:22
  • Hrm, I interpret questions like this as asking *why* (or why not). Strictly yes/no answers aren't very useful because they don't help anyone to understand things. *Why* is it an excellent idea? – Cody Gray - on strike Apr 04 '11 at 12:24
  • I've added some. I am stunned people are suggesting it's not good practise / not a good idea. Do these people write apps that are used by anyone? – Kieren Johnstone Apr 04 '11 at 12:26
  • Whoa, hold on. You can't just say "log/recover". They're totally different things. You should *not* catch the exception just to log it. You should only catch the exception if you can recover from it. But that's precisely why you shouldn't catch the base `Exception` class—by definition, it includes exceptions that you *can't possibly* recover from. I agree that it might be a good idea to catch *specific* exceptions derived from the base class, but people are saying it's never a good idea to catch `System.Exception`. I can't speak for them, but I've certainly written production apps. – Cody Gray - on strike Apr 04 '11 at 12:28
  • I don't agree - if you can't handle it, and you're at the top level, log it. Otherwise you've no idea why or how your thread or app terminated. You could rely on the OS but that's completely out of your control, isn't it? You need to know what happened somehow, surely – Kieren Johnstone Apr 04 '11 at 12:29
  • +1. Of course top-level exception handlers are a good idea, except in certain ivory towers. For an example, you only need to look at System.ComponentModel.BackgroundWorker, which does exactly this. – Joe Apr 04 '11 at 12:30
0

Officially it's not good practice, but sometimes it is done.

The arguments are exactly the same as they are for doing this on a "main" thread.

One major problem is that if you swallow errors like this, then your application may function very incorrectly - e.g. it might overwrite crucial user data - rather than terminating.


If you do chose to go this route, you might want to be careful to exclude ThreadAbortException from your catching - this is an "expected exception" if anyone ever aborts a worker thread (which may or may not be the case in your app)

Stuart
  • 66,722
  • 7
  • 114
  • 165
  • I don't agree; he says the top level of a thread. That means when a thread fails, you can recover or log - it won't 'swallow' exceptions will it? – Kieren Johnstone Apr 04 '11 at 12:26
  • 1
    I think the answer is that it depends on what the exception is... how are you deciding whether to recover or log? If you are proposing there are certain types of errors where you want your application to recover then I'm happy for you to recommend that as "best practice" - but that's not catching `System.Exception`. If you want to recommend some generic "log and exit" pattern as best practice then I'm not going to argue... However, I'm still going to stick by "officially it's not good practice" - I can't recall anyone like Richter recommending this? – Stuart Apr 04 '11 at 12:59
0

Only handle exception you could do something about. To not show yellow screen I personally prefer to catch unhandeld excetpion in the global.asax event Application_error

Ivo
  • 3,406
  • 4
  • 33
  • 56
-2

We are generally not meant to create new thread directly. Only in a few circumstances it is acceptable.

So if you do use new Thread() especially in UI , that would be frowned upon.

It is encouraged to use BackgroundWorker or Task<T> which encapsulates thread exception handling so no exception handling in terms of catch block would be necessary.


These 4 scenarios are acceptable cases where you want your own thread (From CLR via C#):

I highly recommend that you use the thread pool to execute asynchronous compute-bound operations whenever possible. However, there are some occasions when you might want to explicitly create a thread dedicated to executing a particular compute-bound operation. Typically, you'd want to create a dedicated thread if you're going to execute code that requires the thread to be in a particular state that is not normal for a thread pool thread. For example, I'd create a dedicated thread if I wanted the thread to run at a special priority (all thread pool threads run at normal priority, and you should not alter a thread pool thread's priority). I would also consider creating and using my own thread if I wanted to make the thread a foreground thread (all thread pool threads are background threads), thereby preventing the application from dying until my thread has completed its task. I'd also use a dedicated thread if the compute-bound task were extremely long running; this way, I would not be taxing the thread pool's logic as it tries to figure out whether to create an additional thread. Finally, I'd use a dedicated thread if I wanted to start a thread and possibly abort it prematurely by calling Thread's Abort method (discussed in Chapter 21, "CLR Hosting and AppDomains").

Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • -1: This is a going too far. Of *course* we are meant to use threading directly when it's the most suitable option. – Jon Apr 04 '11 at 12:13
  • `I highly recommend that you use the thread pool`. So use thread pool (used by `Task` and `BackgroundWorker`) instead of creating your own thread. – Aliostad Apr 04 '11 at 12:27
  • @Aliostad: Is there a conceptual difference between `new Thread` and `ThreadPool.QueueUserWorkItem` in the context of the current topic? You are confusing the issue of *managing thread lifetimes* with the current issue of exception handling. – Jon Apr 04 '11 at 12:38
  • Is there a conceptual difference? Yes, big difference and according to Jeff, `new Thread` should not appear in your code other than those 4 cases which none of them relevant to what our friend needed. I did not confuse, **I had a lateral approach to the question** as he was concerned with doing something which *he really did not need to if he would have stuck to threading best practices*. – Aliostad Apr 04 '11 at 12:44
  • Go to the implementation of the `ThreadPool` and see the difference. As for our points of view, they are different, I am not expecting to convert you neither should you. I am happy with my 2 downvotes. My answers are not probably palatable but I have a clear conscience that they are correct - as much as I can say. – Aliostad Apr 04 '11 at 13:05
  • In my case this is a very long running thread, that will only terminate when the system is closed. – Michael Apr 04 '11 at 14:50