什么是终止连续运行WinForm应用程序的线程的正确方法?

时间:2017-05-07 22:52:06

标签: c# multithreading winforms

我有一个单元测试,我通过调用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(),但它永远不会结束!因为应用程序消息循环继续运行,除非我调用ExitExitThread,因为我只有Thread而且我需要在其中调用它们Files.createDirectories()。线程。

那么,我该怎么办?如何在没有异常的情况下安全地结束此线程?

1 个答案:

答案 0 :(得分:1)

您需要某种线程间通信来告诉WinForms线程自行终止。然后,使用带有超时的Thread.Join()来等待它正常退出,如果它在这段时间内无法加入,你可以使用Thread.Abort()来硬杀它。

由于它是WinForms线程,因此它可能将大部分时间花在消息泵上,等待系统消息转换为事件。您可以利用此功能并向该线程的消息泵发送WM_QUIT消息,告知其关闭。您必须P / invoke PostThreadMessage才能这样做。除了线程ID之外,你可以做到这一点。

如果您可以修改WinForms线程代码,那么您可以执行更多托管和更少p / invoke魔术,例如使用CancellationTokenSource发出退出信号,并让WinForms线程的主要形式订阅Token.Register的{​​{1}}并使用它来通知您要退出。然后,您的控制线程可以调用CancellationTokenSource方法向WinForms线程发出信号,告知它应该退出。