异常处理:Thread v / s Task

时间:2017-11-14 05:54:32

标签: c#

线程版本导致未处理的异常,这会导致应用程序崩溃但任务版本不会崩溃。两者都运行完全相同的方法有人可以解释异常行为中这种差异的原因吗?

主题版本:

            try
            {
                new Thread(new ThreadStart(DoWork)).Start();  // do work throws exception
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

        static void DoWork()
        {
            Console.WriteLine("in thread");
            throw new Exception();
        }

任务版本:

      var errorTask = Task.Factory.StartNew<Func<string>>(() =>
                {
                    Console.WriteLine("in task");
                    throw new Exception();
                });

            try
            {
                string result = errorTask.Result();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

2 个答案:

答案 0 :(得分:3)

Thread.Start启动新线程,但您在另一个线程中处理异常:

try
{
    // DoWork throws exception in new thread;
    // threads don't catch exceptions out-of-the-box
    new Thread(new ThreadStart(DoWork)).Start();
}
catch (Exception e)
{
    // you're handling exception in "old" thread
    Console.WriteLine(e);
}

Task.Factory.StartNew启动新的任务。任务捕获其中的异常以设置其Status属性:

var errorTask = Task.Factory.StartNew<Func<string>>(() =>
{
    Console.WriteLine("in task");

    // this exception will be caught in Task's base code,
    // since tasks catch exceptions thrown by task methods;
    // note, that this will be wrapped into AggregateException
    throw new Exception();
});

当您尝试获取Task.Result并且任务处于故障状态时,它只会重新抛出异常:

// this will re-throw exception in calling thread
string result = errorTask.Result;

这就是你的第二个catch抓住它的原因。

答案 1 :(得分:1)

为了阐明这个话题,可以咨询Task.Result<TResult>() AggregateExceptiondocumentationTask.Wait(),了解它的价值。

抛出异常(特别是AggregateException.InnerExceptions)是

  

在执行任务期间抛出了异常。 Task集合包含有关异常或异常的信息。

Result是一种托管线程(用非常简单的术语),它给了我们一些优点,例如访问Waitawait(或使用Thread)时的此异常处理。另一方面,try / catch将与您调用它的方法分开执行。你启动线程(几乎)立即离开try / catch块。没有办法知道该线程存在关联的try / catch。基本上,线程对调用函数一无所知。反过来说,如果调用函数阻塞了自己的线程来等待它创建的线程,只是为了使用/ZeroBraneStudio/bin/lua53.dll,这基本上会使创建新线程变得无用。