44

我有以下引发异常的代码:

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

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


相关:.Net ThreadPool 线程的异常

4

6 回答 6

71

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

        ThreadPool.QueueUserWorkItem(state =>
                                         {
                                             try
                                             {
                                                 action();
                                             }
                                             catch (Exception ex)
                                             {
                                                 OnException(ex);
                                             }
                                         });
于 2009-04-15T21:43:34.513 回答
25

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

于 2009-04-15T21:41:50.443 回答
19

如果您使用的是 .Net 4.0,则可能值得研究Task类,因为它可以为您解决这个问题。

相当于您的原始代码,但使用任务,看起来像

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

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

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);
于 2011-09-12T18:51:07.850 回答
3

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

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

这是我最近使用的一个项目中的一些示例代码...
HasException 是共享布尔值...

    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;
    }
于 2009-04-15T21:41:28.743 回答
1

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

于 2009-04-15T21:41:12.630 回答
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);
    }
}
于 2019-06-18T05:20:39.997 回答