如何从用C#编写的控制台应用程序中的工作线程中捕获错误

时间:2011-03-16 12:37:49

标签: c# multithreading parallel-processing threadpool

我目前有一个小型控制台应用程序,它运行许多任务(使用 Parallel.ForEach ),并且这些任务中的每一个都使用 ThreadPool.QueueUserWorkItem 创建子线程

我希望应用程序能够处理这些任务/线程抛出的任何异常。

如果线程抛出任何错误或者它们会不会消失, try..catch 会围绕 Parallel.ForEach 语句吗?

编辑:这些子线程模拟系统的用户。请参阅this question.

5 个答案:

答案 0 :(得分:4)

声明周围不会做这个工作。你可以这样做:

public static void Main(string[] args)
{             
    string[] files = System.IO.Directory.GetFiles(@".", "*.*");      

    Parallel.ForEach(files, x =>
    {
      try
      {
        MyAction(x);
      }
      catch(Exception ex)
      {
        Console.WriteLine(ex.ToString());
      }
    });        
}

static void MyAction(string x)
{      
  throw new ApplicationException("Testing: " + x);
}

答案 1 :(得分:2)

不要使用QUWI。我简要比较了后台任务类型on my blogTaskBackgroundWorkerDelegate.BeginInvokeThreadPool.QueueUserWorkItemThread)。

对于后台任务,Task是明显的赢家。 QueueUserWorkItem相比之下是非常低级别的。

特别是,您的问题是错误传播,Task内置了对QueueUserWorkItem完全缺乏的支持。通过将委托包装在try / catch中,将 自己构建它,将异常存储为委托参数的一部分(或作为lambda表达式的绑定变量) ),稍后显式检查,并执行一些technically unsupported reflection以保留堆栈跟踪。

但为什么要这么麻烦? Task支持开箱即用的错误传播。

答案 2 :(得分:1)

您可以使用try / catch处理所有异常,例如:

try
{
    MyParallelMethod();
}
catch(Exception e)
{
    //...
}

在你的方法中,做一些类似的事情:

public void MyParallelMethod()
{
    var data = new List<String>(); 
    //...

    Parallel.ForEach(data, d =>
    {
        try
        {
            //...
        }

        catch (Exception e) 
        { 
            //...    
        }
    });
 }

答案 3 :(得分:0)

  

如果线程抛出任何错误或者它们会消失,是否会将try.catch的Parallel.ForEach语句包围起来?

不,你需要把try / catch放在子线程中。

答案 4 :(得分:0)

必须在任务本身(每个作业)中实现错误处理。您需要确保要创建的任务处理异常。

Parallel.ForEach将不会为您处理它,因为异常将不会在调用Parallel.ForEach的线程中引发。

替代方法是使用Task<T>