4

I am handling thread exceptions but I want to get the name of the Thread that the exception occurred on. It appears that when the thread exception fires the event stays on the main thread although I think the exception could have occurred on a different thread.

static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
    ShowFaultDialog(e.Exception, "(Application) Thread Exception [" + System.Threading.Thread.CurrentThread.Name + "]");
}
James
  • 2,812
  • 3
  • 22
  • 33
  • 1
    By the time that the thread exception has been caught, the thread that caused it has already gone away, so unfortunately there is no way for you to obtain the thread ID at this point. The best you can do is inspect the stack in the Exception to work out which code threw the exception. If it's in code you can modify, you could then add try/catch handling to the throwing code to report the thread ID. – Matthew Watson Aug 02 '12 at 09:11
  • I looked at the threads in the Thread debug window of VS and yes, the thread does appear to have been destroyed already. Duw – James Aug 02 '12 at 09:40
  • Actually the name is available but the main thread does not have a name despite what VS 2010 reports. – James Aug 02 '12 at 11:16

4 Answers4

2

In static void Main():

Thread.CurrentThread.Name = "Main Thread";

VS 2010 shows the main thread as having a 'Name' of "Main Thread" but actually the thread name is null.

James
  • 2,812
  • 3
  • 22
  • 33
1

If you mean handling of Application.ThreadException event: it fires only on exceptions, that was thrown from WinForms threads. Usually, there's one WinForms thread in application: the main thread.

UPDATE.

Here's sample that demonstrating Application.ThreadException and AppDomain.UnhandledException behavior difference:

1) Program class:

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        Application.Run(new Form1());
    }

    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Debug.WriteLine(Thread.CurrentThread.Name);
    }

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        Debug.WriteLine(Thread.CurrentThread.Name);
    }
}

2) Main form (a form with two buttons) code-behind:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        throw new InvalidOperationException();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        new Thread(() => { throw new InvalidOperationException(); })
        {
            Name = "Worker Thread"
        }.Start();
    }
}

When you are clicking on button1, you're throwing exception from WinForms thread. So, this exception will be handled at Application_ThreadException by default.

When you are clicking on button2, you're throwing exception from worker thread, which is not a WinForms thread. Application.ThreadException isn't fired in this case, instead AppDomain.UnhandledException event is fired (and CurrentDomain_UnhandledException is called, producing 'Worker Thread' line in output window).

Dennis
  • 37,026
  • 10
  • 82
  • 150
  • Thread exceptions can fire from any thread within the .NET app. I have three or four threads running as well as the main thread. – James Aug 02 '12 at 09:47
  • @James, from MSDN: 'This event allows your Windows Forms application to handle otherwise unhandled exceptions that occur in Windows Forms threads. To catch exceptions that occur in threads not created and owned by Windows Forms, use the UnhandledException event handler'. See remarks section here: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.threadexception.aspx – Dennis Aug 02 '12 at 09:54
  • 1
    I don't see the relevance as this is a ThreadException that is being fired and the 3rd party component is winforms. – James Aug 02 '12 at 10:00
  • 1
    @James, I've updated my answer. I hope, it will be more clear to understand. – Dennis Aug 02 '12 at 10:20
  • Hi, so you mean that Main thread throws thread exceptions and all other System.Threading.Threads throw 'UnhandledException' exceptions. – James Aug 02 '12 at 10:47
  • 1
    @James, to be more precise: when the main thread of WinForms application throws unhandled exception, it **may** be routed to the `Application.ThreadException` event handler (and may be not, see UnhandledExceptionMode enum). When any worker thread (created using `ThreadPool` methods, TPL API, or constructed directly by calling `Thread` constructor) throws unhandled exception, it can be routed to `AppDomain.UnhandledException` event handler only (there's one issue when using tasks - their unhandled exceptions are being thrown at finalizer thread, not the thread which was executed a task). – Dennis Aug 02 '12 at 11:43
  • In addition: when `UnhandledExceptionMode` is set to `ThrowException`, all of unhandled exceptions thrown from GUI thread, also will be routed to `AppDomain.UnhandledException` event handler. – Dennis Aug 02 '12 at 11:50
0

Use an incrememnted numerical variable (such as byte) to give each thread it's own name eg

string threadname = "Thread" + threadnumber

And then use the catch statement to notify you like so:

ShowFaultDialog(e.exception, threadname)

That way you'll be able to tell which thread it is, in theory.

Pharap
  • 3,826
  • 5
  • 37
  • 51
  • Thanks, my threads already have names though. As Matthew Watson pointed out by this time the thread has already been destroyed. – James Aug 02 '12 at 09:42
  • Well, it was worth a try. I don't have much experience with threading, and I'm fairly new to C#. I was just trying for something logical. If you know what the exception is, you could always try and output the name to a separate thread monitoring the other threads before the exception occurs. – Pharap Aug 02 '12 at 09:43
  • Unfortunately the exception is in a third party component so any capturing is difficult. I think that capturing the thread name for the thread that has the exception may not be possible unless the thread object in .NET has a separate capture event. – James Aug 02 '12 at 09:50
  • Try isolating the exception first, it will give you a better idea of what's going wrong. If it's something numerical, like something going over its limit, that should be easy enough to catch and isolate by using an if to test if adding to it or subtracting from it would cause an error. In short, make a separate exception handler for different exceptions until you isolate the cause. Understanding what's going on makes debugging much easier. – Pharap Aug 02 '12 at 10:02
  • I actually already know where the exception comes from I just want to log the thread name in my logging. I don't think the name can be recovered because by the time the event fires the thread has been destroyed. – James Aug 02 '12 at 10:06
  • If you know what the exception is and where it occurs, you can test for it before it happens. For example, if I had a byte variable and was incrementing it, to avoid getting an exception where it goes over it's maximum value, I would test if adding to it would cause an exception before I added to it. eg: if ((bytevalue+1)>256) {//notify me and dont increment} elseif ((bytevalue+1)<=256) {bytevalue++} – Pharap Aug 02 '12 at 10:08
  • Unfortunately the exception occurs in a 3rd party winforms component. – James Aug 02 '12 at 10:12
  • Ok, what exactly is the exception? If I know what the exception is/what's causing it, I can probably think of a way to test for it before it happens. – Pharap Aug 02 '12 at 10:14
0

As I understand from MSDN the Application_ThreadException event allows Windows Forms applications to handle unhandled exceptions that occur in Windows Forms threads and when you reach this event you are in your main UI thread. So it will print always the same.

Have you checked the Exception.TargetSite property? This property gives you back the method name and signature where the exception occurred.

Steve
  • 213,761
  • 22
  • 232
  • 286