13

Recently i have attended an interview . A code snippet is given to me.I know,the interviewer took it from albhari's threading sample.

public static void Main() 
{
    try 
    {
        new Thread (Go).Start();
    }
    catch (Exception ex)
    {
        // We'll never get here!
       Console.WriteLine ("Exception!");
    }
}

static void Go() { throw null; }

The modification of the above code as

public static void Main()
{
    new Thread (Go).Start();
}

static void Go() 
{
    try 
    {
        ...
        throw null; // this exception will get caught below
        ...
    }
    catch (Exception ex) 
    {
        Typically log the exception, and/or signal another thread
        that we've come unstuck
        ...
    }
}

would be the good candidate to handle the exception.

I have been asked, "Except the above trail what are the other alternatives would fit as good solution?. It was hard to find the alternative,so i raise it here to gather your suggestion.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
user184805
  • 1,839
  • 4
  • 19
  • 16

5 Answers5

20

Exception thrown in a thread normally couldn't be caught in another thread.

You'd better to catch it in function Go and pass it to main thread explicitly.

However, if you just want to log all unhandled messages from all threads, you may use AppDomain.UnhandledException event or equivalent events at Application class if you are developing WinForms or WPF app.

elder_george
  • 7,849
  • 24
  • 31
  • 13
    ...but be aware that you cannot handle the exception in AppDomain.UnhandledException, you get notified but the application will be shut down anyways. – Lucero Oct 12 '09 at 12:13
  • 2
    It is possible to prevent application stopping by setting v1.x compatibility mode. For this a element must be added to app.config in the – elder_george Oct 13 '09 at 05:20
4

what are the other alternatives would fit as good solution?.

Solution to what? What problem are you trying to solve?

If you use BackgroundWorker, as opposed to Thread, it has an RunWorkerCompleted event, and within that you can check the RunWorkerCompletedEventArgs param for the Error property. This generally is used in WinForms or WPF apps, because there is good support for BackgroundWorker in the Visual Studio designer.

You could also define a delegate for Go(), and call BeginInvoke() on it. Of course you need the EndInvoke() too.

Also, it's generally not a good idea to start up random threads. ThreadPool.QueueUserWorkItem, BackgroundWorker, or asynch delegates all use the ThreadPool, and are recommended.

Cheeso
  • 189,189
  • 101
  • 473
  • 713
  • well what I mean is this: the original code was broken. Your first option is an alternative. IF it is satisfactory, then you need no other alternatives. What problem are you trying to solve? "an alternative to the original code" could be *anything*. You could submit code that solves sudoku puzzles - that would be an alternative. Would it be appropriate? Without requirements, who can say? – Cheeso Oct 12 '09 at 12:22
  • No sir,the interviewer asked that question. :) so i did not tell anything.Moreover i did not the know how to tackle it. :) Thanks for your suggestion. – user184805 Oct 12 '09 at 12:34
  • 2
    @Cheeso, please read the question correctly, no one is in need of any suggestion, he faced this at an interview where the smart guy tells him to find an alternative, i believe the requester truely knows enough about everything what you are suggesting. – Akash Kava Oct 12 '09 at 12:36
2

There are alternatives listed on Joe Albahari's website: http://www.albahari.com/threading/#_Exception_Handling

"There are, however, some cases where you don’t need to handle exceptions on a worker thread, because the .NET Framework does it for you. These are covered in upcoming sections, and are:
-Asynchronous delegates
-BackgroundWorker
-The Task Parallel Library (conditions apply)"

jrupe
  • 1,399
  • 1
  • 11
  • 11
1

You can use the AppDomain.UnhandledException event

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
1

I think this is the easiest way is:

BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler((object sender2, DoWorkEventArgs e2) =>
{
    throw new Exception("something bad");
    e2.Result = 1 + 1;
});
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler((object sender2, RunWorkerCompletedEventArgs e2) =>
{
    if (e2.Error != null)
    {
        Console.WriteLine("Error: " + e2.Error.Message);
    }
});
bw.RunWorkerAsync();

but there is another way that some might prefer if you want to synchronize the thread (perhaps this is on a thread other than the GUI thread):

    private class FileCopier
    {
        public bool failed = false;
        public Exception ex = null;
        public string localPath;
        public string dstPath;
        public FileCopier(string localPath, string dstPath)
        {
            this.localPath = localPath;
            this.dstPath = dstPath;
        }

        public void Copy()
        {
            try{
                throw new Exception("bad path");
            }catch(Exception ex2)
            {
                ex = ex2;
                failed = true;
            }
        }
    }

    public static void Main()
    {
        FileCopier fc = new FileCopier("some path", "some path");
        Thread t = new Thread(fc.Copy);
        t.Start();
        t.Join();
        if (fc.failed)
            Console.WriteLine(fc.ex.Message);
    }

Note that the second example would make more sense if you have several threads and you loop through them and join all...but I kept the example simple.

the 3rd pattern would be using Task Factory which is cleaner:

private static test(){
    List<Task<float>> tasks = new List<Task<float>>();
    for (float i = -3.0f; i <= 3.0f; i+=1.0f)
    {
        float num = i;
        Console.WriteLine("sent " + i);
        Task<float> task = Task.Factory.StartNew<float>(() => Div(5.0f, num));
        tasks.Add(task);
    }

    foreach(Task<float> t in tasks)
    {
        try
        {
            t.Wait();
            if (t.IsFaulted)
            {
                Console.WriteLine("Something went wrong: " + t.Exception.Message);
            }
            else
            {
                Console.WriteLine("result: " + t.Result);
            }
        }catch(Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message);
        }

    }
}

private static float Div(float a, float b)
{
    Console.WriteLine("got " + b);
    if (b == 0) throw new Exception("Divide by zero");
    return a / b;
}
max
  • 9,708
  • 15
  • 89
  • 144