重复:How to catch exceptions from a ThreadPool.QueueUserWorkItem?
我在.Net ThreadPool上排队多个代表,用于大量独立的远程调用,这些调用本身调用多个数据库和其他脱机资源。通过在ThreadPool上对这些调用进行排队,我可以同时运行它们并最小化整体延迟。
private void CompleteAndQueuePayLoads(IEnumerable<UsagePayload> payLoads)
{
List<WaitHandle> waitHndls = new List<WaitHandle>();
foreach (UsagePayload uPyLd in payLoads)
{
ManualResetEvent txEvnt = new ManualResetEvent(false);
UsagePayload uPyLd1 = uPyLd ;
ThreadPool.QueueUserWorkItem(
delegate
{
if (!uPyLd1 .IsComplete)
// IEEDAL.GetPayloadReadings is long running DB call
try { IEEDAL.GetPayloadReadings(uPyLd1 ); }
catch (IEEAccessException iX)
{
log.Write(log.Level.Error,
"IEEWSDAL.CompleteAndQueuePayLoads " +
" Delegate Failed " +
iX.Message, iX);
txEvnt.Set();
throw; // this causes parent thread to crash!
// was going to try Thread.Abort next ...
// Thread.CurrentThread.Abort();
}
UsageCache.PersistPayload(uPyLd1 );
SavePayLoadToProcessQueueFolder(uPyLd1 );
txEvnt.Set();
});
waitHndls.Add(txEvnt);
}
util.WaitAll(waitHndls.ToArray()); //To waitone on > 64 waithandles
}
但是整个批处理需要以事务方式处理,例如,如果所有子线程都成功,则只允许继续执行父线程的输出。我编写了子线程以在失败时抛出自定义异常,但我发现这会导致父线程崩溃,因为这些异常无法在父线程中“捕获”...
我已经读过CLR发生的UnHandledExceptionEvent抛出,但是我需要在这些子线程被排队并生成的方法中“处理”这个异常,以便根据成功控制立即下游处理孩子三人......我该怎么办呢?
答案 0 :(得分:3)
如果线程失败,您可以在CompleteAndQueuePayLoads函数的局部变量中标记至少发生一次失败,并添加要在以后检查的异常/失败变量。
答案 1 :(得分:2)
我在目前的项目中做了很多。我采用的方法是制作我自己的调度程序,它接受委托,将其添加到我自己的队列中,然后运行它们来处理最后的同步等。
我在这种情况下使用的“技巧”是不直接在线程池上调用委托,而是在我的调度程序中调用一个方法来包装委托并更优雅地处理异常。这样,实际的内部方法调用总是以适当的(对我来说)方式处理。
当发生异常时,我的调度程序会收到通知并停止安排将来的任务(这是一个很好的奖励),但也会告诉调用者有一个例外。
答案 2 :(得分:1)
您可以查看3.5的并行库扩展。您可以在代码块上使用Parallel.Invoke来完成您正在尝试的操作。