我有以下引发异常的代码:
ThreadPool.QueueUserWorkItem(state => action());
当操作引发异常时,我的程序崩溃。处理这种情况的最佳做法是什么?
我有以下引发异常的代码:
ThreadPool.QueueUserWorkItem(state => action());
当操作引发异常时,我的程序崩溃。处理这种情况的最佳做法是什么?
您可以像这样添加 try/catch:
ThreadPool.QueueUserWorkItem(state =>
{
try
{
action();
}
catch (Exception ex)
{
OnException(ex);
}
});
如果您有权访问action
的源代码,请在该方法中插入一个 try/catch 块;否则,创建一个tryAction
将调用包装action
在 try/catch 块中的新方法。
如果您使用的是 .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);
在另一个线程上,(在您“排队”的方法中,添加一个 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;
}
我通常做的是在 action() 方法中创建一个大的 try ... catch 块,然后将异常存储为私有变量,然后在主线程中处理它
简单代码:
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);
}
}