如何从ThreadPool.QueueUserWorkItem中捕获exception?
我有下面的代码引发exception:
ThreadPool.QueueUserWorkItem(state => action());
当动作引发exception时,我的程序崩溃。 处理这种情况的最佳做法是什么?
相关: .Net ThreadPool线程的例外
如果您有权访问action
的源代码,请在该方法中插入try / catch块; 否则,创build一个新的tryAction
方法,将调用的action
包装在try / catch块中。
你可以像这样添加try / catch:
ThreadPool.QueueUserWorkItem(state => { try { action(); } catch (Exception ex) { OnException(ex); } });
如果您使用的是.Net 4.0,则可能需要调查Task类,因为它可以为您处理此问题。
你原来的代码相当于使用任务,看起来像
Task.Factory.StartNew(state => action(), state);
要处理exception,可以将继续添加到由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);
在另一个线程上(在“排队”的方法中,添加一个try catch子句…。然后在捕获中,将捕获的exception放入一个共享的Exceptionvariables(对主线程可见)。
然后在你的主线程,当所有排队的项目已经完成(使用一个等待句柄数组为这个)检查是否有一个线程填充共享exception与例外…如果它,重新抛出或处理适当的…
这里是一个最近的项目的一些示例代码,我用这个…
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; }
我通常做的是在action()方法中创build一个大的try … catch块,然后将该exception存储为一个私有variables,然后在主线程中处理它