我有一个单元测试,我通过调用Application.Run
创建一个运行标准WinForms应用程序的后台线程。
这是线程的创建:
var startSignal = new ManualResetEvent(false);
ThreadStart threadStart = () =>
{
syncContext = new WindowsFormsSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(syncContext);
startSignal.Set();
Application.Run();
};
var thread = new Thread(threadStart)
{
IsBackground = true,
};
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
在TearDown
方法中,我想终止此线程。当我使用Thread.About
时,即使使用ThreadAbortException
/ try
,我也会获得catch
,因为根据documentation自动重新抛出异常:
ThreadAbortException
是一个特殊的异常,可以被应用程序代码捕获,但会在catch
块的末尾重新抛出,除非调用ResetAbort
。
这个自动抛出的异常未处理,并且在使用ReSharper测试运行器时会破坏其他测试运行。
我虽然使用thread.Join()
,但它永远不会结束!因为应用程序消息循环继续运行,除非我调用Exit
或ExitThread
,因为我只有Thread
而且我需要在其中调用它们Files.createDirectories()
。线程。
那么,我该怎么办?如何在没有异常的情况下安全地结束此线程?
答案 0 :(得分:1)
您需要某种线程间通信来告诉WinForms线程自行终止。然后,使用带有超时的Thread.Join()来等待它正常退出,如果它在这段时间内无法加入,你可以使用Thread.Abort()来硬杀它。
由于它是WinForms线程,因此它可能将大部分时间花在消息泵上,等待系统消息转换为事件。您可以利用此功能并向该线程的消息泵发送WM_QUIT
消息,告知其关闭。您必须P / invoke PostThreadMessage
才能这样做。除了线程ID之外,你可以做到这一点。
如果您可以修改WinForms线程代码,那么您可以执行更多托管和更少p / invoke魔术,例如使用CancellationTokenSource
发出退出信号,并让WinForms线程的主要形式订阅Token.Register
的{{1}}并使用它来通知您要退出。然后,您的控制线程可以调用CancellationTokenSource
方法向WinForms线程发出信号,告知它应该退出。