线程意外退出时引发的异常
本文关键字:异常 意外 退出 线程 | 更新日期: 2023-09-27 18:24:59
我有一个工作线程,当它终止时,它会发出事件信号。然后将此事件编组到主线程,以通知它工作线程的终止。当工作线程遇到未处理的异常时,我希望由主线程的错误处理系统来处理此异常。因此,工作线程设置一个指示其意外终止的属性,并将异常保存在另一个属性中,然后发出事件信号并退出。
在事件被编组到主线程之后,我想抛出一个新的异常,将原始异常设置为内部异常。我的问题是:这个新异常的类型应该是什么?对于这种情况,是否有特定的System.somethingException?我应该为这种特定情况设计自己的Exception类,还是应该抛出一个带有适当消息的标准System.Exception?
C#-伪代码:
class MyThread
{
public TerminationState Termination { get; private set; }
public Exception UncaughtException { get; private set; }
public delegate void ThreadTerminatedDelegate(MyThread thread);
public event ThreadTerminatedDelegate ThreadTerminated;
private void run()
{
try
{
doSomeWork();
}
catch(Exception e)
{
UncaughtException = e;
Termination = TerminationState.AbortOnException;
ThreadTerminated(this);
return;
}
Termination = TerminationState.NormalTermination;
ThreadTerminated(this);
}
}
class MainThread
{
private MyThread myThread = new MyThread();
private void run()
{
myThread.ThreadTerminated += handleTermination;
myThread.Start();
}
private void handleTermination(MyThread thread)
{
if (InvokeRequired)
{
MyThread.ThreadTerminatedDelegate cb = new MyThread.ThreadTerminatedDelegate(handleTermination);
BeginInvoke(cb, new object[] { thread });
}
else
{
if (thread.Termination == TerminationState.AbortOnException)
{
if (isFatal(thread.UncaughtException))
throw new Exception("", thread.UncaughtException); //what to do here?
else
fixTheProblem();
}
else
{
//normal wrapping up
}
}
}
}
我相信,通过在Task
中执行后台工作,然后在明确计划在主线程上运行的任务的延续中处理任何异常,可以对未处理的后台异常执行所有必要的异常处理。您可以为延续指定其他选项,但这应该涵盖您的场景。
Task.Factory.StartNew(
() =>
{
// Do some work that may throw.
// This code runs on the Threadpool.
// Any exceptions will be propagated
// to continuation tasks and awaiters
// for observation.
throw new StackOverflowException(); // :)
}
).ContinueWith(
(a) =>
{
// Handle your exception here.
// This code runs on the thread
// that started the worker task.
if (a.Exception != null)
{
foreach (var ex in a.Exception.InnerExceptions)
{
// Try to handle or throw.
}
}
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext()
);
另一个有用的链接是MSDN的异步编程模式。它确定了在应用程序中实现异步操作的3种主要方法。您当前的实现听起来与本文所称的EAP(基于事件的异步模式)非常相似。
我个人更喜欢TAP(基于任务的异步模式),它依赖于.NET 4.0 TPL(任务并行库)。由于其语法的简单性和广泛的功能,它非常值得掌握。
来自MSDN:
- 异步编程模型(APM)模式(也称为IAsyncResult模式),其中异步操作需要Begin和End方法(例如,异步写操作需要BeginWrite和EndWrite)。对于新的开发,不再建议使用此模式。有关更多信息,请参阅异步编程模型(APM)
- 基于事件的异步模式(EAP),它需要一个具有Async后缀的方法,还需要一个或多个事件、事件处理程序委托类型和EventArg派生类型。EAP是在.NET Framework 2.0中引入的。不再建议进行新的开发。有关更多信息,请参阅基于事件的异步模式(EAP)
- 基于任务的异步模式(TAP),它使用单个方法来表示异步操作的启动和完成。TAP是在.NET Framework 4中引入的,是.NET Framework中异步编程的推荐方法。有关更多信息,请参阅基于任务的异步模式(TAP)
另外,不要忘记可靠的BackgroundWorker
类。很长一段时间以来,这个类一直是我的主要内容,尽管TAP对它有点不赞成,但它仍然可以完成任务,并且非常容易理解和使用。
// Create a new background worker.
var bgw = new BackgroundWorker();
// Assign a delegate to perform the background work.
bgw.DoWork += (s, e) =>
{
// Runs in background thread. Unhandled exceptions
// will cause the thread to terminate immediately.
throw new StackOverflowException();
};
// Assign a delegate to perform any cleanup/error handling/UI updating.
bgw.RunWorkerCompleted += (s, e) =>
{
// Runs in UI thread. Any unhandled exception that
// occur in the background thread will be accessible
// in the event arguments Error property.
if (e.Error != null)
{
// Handle or rethrow.
}
};
// Start the background worker asynchronously.
bgw.RunWorkerAsync();