C# 如何从 ThreadPool.QueueUserWorkItem 中捕获异常?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/753841/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to catch exceptions from a ThreadPool.QueueUserWorkItem?
提问by Michael Hedgpeth
I have the following code that throws an exception:
我有以下代码引发异常:
ThreadPool.QueueUserWorkItem(state => action());
When the action throws an exception, my program crashes. What is the best practice for handling this situation?
当操作抛出异常时,我的程序崩溃。处理这种情况的最佳做法是什么?
采纳答案by Tormod Fjeldsk?r
If you have access to action
's source code, insert a try/catch block in that method; otherwise, create a new tryAction
method which wraps the call to action
in a try/catch block.
如果您有权访问action
的源代码,请在该方法中插入一个 try/catch 块;否则,创建一个新tryAction
方法,将调用包装action
在 try/catch 块中。
回答by oscarkuo
What I usually do is to create a big try ... catch block inside the action() method then store the exception as a private variable then handle it inside the main thread
我通常做的是在 action() 方法中创建一个大的 try ... catch 块,然后将异常存储为私有变量,然后在主线程中处理它
回答by Charles Bretana
On the other thread, (in the method you are "queueing" up, add a try catch clause... .Then in the catch, place the caught exception into a shared Exception variable (visible to the main thread).
在另一个线程上,(在您“排队”的方法中,添加一个 try catch 子句...。然后在 catch 中,将捕获的异常放入共享的 Exception 变量中(对主线程可见)。
Then in your main thread, when all queued items have finished (use a wait handle array for this) Check if some thread populated that shared exception with an exception... If it did, rethrow it or handle it as appropriate...
然后在您的主线程中,当所有排队的项目都完成时(为此使用等待句柄数组)检查某个线程是否使用异常填充该共享异常...如果是,则重新抛出它或酌情处理...
here's some sample code from a recent project I used this for...
HasException is shared boolean...
这是我最近使用它的一个项目的一些示例代码......
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;
}
回答by Prankster
You can add try/catch like this:
您可以像这样添加 try/catch:
ThreadPool.QueueUserWorkItem(state =>
{
try
{
action();
}
catch (Exception ex)
{
OnException(ex);
}
});
回答by Samuel Hyman
If you're using .Net 4.0, it might be worth investigating the Taskclass because it can take care of this for you.
如果您使用 .Net 4.0,可能值得研究Task类,因为它可以为您解决这个问题。
The equivalent of your original code, but using Tasks, looks like
相当于您的原始代码,但使用任务,看起来像
Task.Factory.StartNew(state => action(), state);
To deal with exceptions you can add a continuation to the Task returned by StartNew. It might look like this:
要处理异常,您可以向 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);
回答by SHO
Simple Code:
简单代码:
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);
}
}