如何从ThreadPool.QueueUserWorkItem中捕获异常?

时间:2009-04-15 21:37:31

标签: c# .net multithreading threadpool

我有以下代码抛出异常:

ThreadPool.QueueUserWorkItem(state => action());

当操作抛出异常时,我的程序崩溃了。处理这种情况的最佳做法是什么?


相关:Exceptions on .Net ThreadPool Threads

6 个答案:

答案 0 :(得分:70)

您可以像这样添加try / catch:

        ThreadPool.QueueUserWorkItem(state =>
                                         {
                                             try
                                             {
                                                 action();
                                             }
                                             catch (Exception ex)
                                             {
                                                 OnException(ex);
                                             }
                                         });

答案 1 :(得分:24)

如果您有权访问action的源代码,请在该方法中插入try / catch块;否则,创建一个新的tryAction方法,该方法将对action的调用包装在try / catch块中。

答案 2 :(得分:19)

如果您使用的是.Net 4.0,可能值得调查Task课程,因为它可以为您解决此问题。

相当于原始代码,但使用“任务”,似乎是

Task.Factory.StartNew(state => action(), state);

要处理异常,您可以为StartNew返回的Task添加延续。它可能看起来像这样:

var task = Task.Factory.StartNew(state => action(), state);
task.ContinueWith(t => 
     {
        var exception = t.Exception.InnerException;
        // handle the exception here
        // (note that we access InnerException, because tasks always wrap
        // exceptions in an AggregateException)
     }, 
     TaskContinuationOptions.OnlyOnFaulted);

答案 3 :(得分:3)

在另一个线程上,(在你正在“排队”的方法中,添加一个try catch子句......然后在catch中,将捕获的异常放入一个共享的Exception变量中(主线程可见)。

然后在你的主线程中,当所有排队的项目都已完成时(为此使用一个等待句柄数组)检查某个线程是否填充了异常的共享异常......如果是,请重新抛出它或根据需要处理它。 ..

这是我最近用于...的项目的一些示例代码 HasException是共享boolean ...

    private void CompleteAndQueuePayLoads(
           IEnumerable<UsagePayload> payLoads, string processId)
    {
        List<WaitHandle> waitHndls = new List<WaitHandle>();
        int defaultMaxwrkrThreads, defaultmaxIOThreads;
        ThreadPool.GetMaxThreads(out defaultMaxwrkrThreads, 
                                 out defaultmaxIOThreads);
        ThreadPool.SetMaxThreads(
            MDMImportConfig.MAXCONCURRENTIEEUSAGEREQUESTS, 
            defaultmaxIOThreads);
        int qryNo = 0;
        foreach (UsagePayload uPL in payLoads)
        {
            ManualResetEvent txEvnt = new ManualResetEvent(false);
            UsagePayload uPL1 = uPL;
            int qryNo1 = ++qryNo;
            ThreadPool.QueueUserWorkItem(
                delegate
                    {
                        try
                        {
                            Thread.CurrentThread.Name = processId + 
                                                      "." + qryNo1;
                            if (!HasException && !uPL1.IsComplete)
                                 IEEDAL.GetPayloadReadings(uPL1, 
                                                  processId, qryNo1);
                            if (!HasException) 
                                UsageCache.PersistPayload(uPL1);
                            if (!HasException) 
                                SavePayLoadToProcessQueueFolder(
                                             uPL1, processId, qryNo1);
                        }
                        catch (MeterUsageImportException iX)
                        {
                            log.Write(log.Level.Error,
                               "Delegate failed "   iX.Message, iX);
                            lock (locker)
                            {
                                HasException = true;
                                X = iX;
                                foreach (ManualResetEvent 
                                          txEvt in waitHndls)
                                    txEvt.Set();
                            }
                        }
                        finally { lock(locker) txEvnt.Set(); }
                    });
            waitHndls.Add(txEvnt);
        }
        util.WaitAll(waitHndls.ToArray());
        ThreadPool.SetMaxThreads(defaultMaxwrkrThreads, 
                                 defaultmaxIOThreads);

        lock (locker) if (X != null) throw X;
    }

答案 4 :(得分:1)

我通常做的是在action()方法中创建一个很大的try ... catch块 然后将异常存储为私有变量,然后在主线程

中处理它

答案 5 :(得分:0)

简单代码:

public class Test
{
    private AutoResetEvent _eventWaitThread = new AutoResetEvent(false);

    private void Job()
    {
        Action act = () =>
        {
            try
            {
                // do work...
            }
            finally
            {
                _eventWaitThread.Set();
            }
        };
        ThreadPool.QueueUserWorkItem(x => act());
        _eventWaitThread.WaitOne(10 * 1000 * 60);
    }
}