C#线程终止和Thread.Abort()


85

在MSDN中,对Thread.Abort()方法的描述为:“调用此方法 通常会终止线程。”

为什么不总是?

在什么情况下它不会终止线程?

还有其他终止线程的可能性吗?

Answers:


60

Thread.Abort()ThreadAbortException在线程上注入a 。线程可以通过调用取消请求Thread.ResetAbort()。此外,还有某些代码部分,例如finally将在处理异常之前执行的块。如果由于某种原因线程被卡在这样的块中,则永远不会在线程上引发异常。

由于调用者在调用时几乎无法控制线程的状态Abort(),因此通常不建议这样做。将消息传递给请求终止的线程。


什么样的消息?您是指方法调用吗?
user101375 2010年

4
这取决于您如何在线程之间传递数据。例如,如果您的线程是带有任务队列的工作线程,则可以对PleaseTerminate消息进行排队,然后让该线程优雅地对其进行处理。
Brian Rasmussen'2

我的线程有一个大问题要解决,那就是没有任务队列。
user101375 2010年

正如我所说,这取决于线程代码的设计方式。也许您可以通过成员变量发出信号。没有可用的实际代码,很难更具体。
Brian Rasmussen

54

在什么情况下它不会终止线程?

这个问题是重复的。

使用Thread.Abort()有什么问题

还有其他终止线程的可能性吗?

是。您的问题是,您永远不要启动无法礼貌地告知要停止的线程,并且该线程会及时停止。如果您必须启动一个线程,该线程可能会(1)难以停止,(2)越野车或最糟糕的(3)对用户不利的线程,那么正确的做法是使一个新进程,在新进程中启动线程,然后在您希望线程中断时终止该进程。唯一可以确保安全终止不合作的线程的事情是操作系统,将其整个过程都销毁了。

有关更多详细信息,请参见我对这个问题的回答过长:

在C#中的循环内使用lock语句

最后一点是相关的,在这里我讨论了在中止线程之前应该等待多长时间杀死线程自己的注意事项。


埃里克(Eric),如果该线程正在等待同步对象(例如EventWaitHandle.WaitOne();),我应该如何礼貌地告诉该线程停止?
科文

5
@Corvin:两个线程之间的约定描述一个线程与另一个线程之间的通信方式,取决于在这些线程上运行的代码的作者。如果您有以下要求:(1)线程X必须永远等待对象,并且(2)线程Y必须能够在有限的时间内完全关闭线程X,那么我认为您有矛盾的要求;决定哪一个获胜。如果是前者,则线程Y将不得不等待。如果是后者,则线程X不应永远等待,而应等待一些时间。
埃里克·利珀特

谢谢回答。考虑以下体系结构:我有一个应用程序,当某个系统范围的事件发生时,它必须将自身最小化。我在该应用程序中有一个线程,等待一个全局命名事件,并在设置该事件时执行其工作。另一方面,我的应用程序可能必须在事件发生之前退出,必须关闭该等待线程。武士编码这种东西的方式是什么?
科文

@Corvin:您可能有一个循环等待事件(短暂的超时),然后检查它是否应该停止尝试等待(这样它可以正常退出)。这样,您可以向线程发出信号,它应该停止,并且只需要等待超时就可以停止它。
凯文·基布尔

2
@Corvin,如果将等待线程设为后台线程,则在应用程序退出之前不必关闭它。
唐·柯比

17

为什么不总是?在什么情况下它不终止线程?

对于初学者来说,线程可能会捕捉到ThreadAbortException并取消其自身的终止。否则,它可能会导致您尝试中止计算所需的时间。因此,运行时无法保证在您请求线程之后线程将始终终止。

ThreadAbortException 有更多:

调用Abort方法销毁线程时,公共语言运行库将引发ThreadAbortException。ThreadAbortException是可以捕获的特殊异常,但是它将在catch块的末尾自动再次引发。引发此异常时,运行时将在结束线程之前执行所有的finally块。由于线程可以在finally块中进行无限制的计算,或调用Thread.ResetAbort()取消中止,因此无法保证线程将永远结束。

您不需要Abort()手动创建线程。如果您只是让线程中的方法返回,那么CLR将为您完成所有的工作。这将正常结束线程。


我确实需要Abort(),因为在该线程(Dispatcher.Run();)上启动了消息循环。如果我理解正确,我需要在线程中调用一个调用return的方法来完成它吗?
user101375'2

7

FileStream.Read()到当前未接收任何内容的命名管道(在等待传入数据时读取调用块)将不会响应Thread.Abort()。它保留在Read()呼叫中。


6

如果线程持有锁并被中止/杀死怎么办?资源仍然停滞

当一个线程调用中止自身而不是其他线程中止时,它可以正常工作。中止,强制终止受影响的线程,即使该线程尚未完成其任务,也不会提供任何清理资源的机会

参考MSDN


请参阅: 托管线程最佳实践


5

我似乎无法中止陷入循环的线程:

//immortal
Thread th1 = new Thread(() => { while (true) {}});

但是,如果在循环过程中处于睡眠状态,我可以中止线程:

//mortal
Thread th2 = new Thread(() => { while (true) { Thread.Sleep(1000); }});

1
这似乎不是事实,我运行了一个测试程序: Console.WriteLine(“ aborting @ {0}”,i);}}); th.Start(); Thread.Sleep(1000); th.Abort(); th.Join(); }
Weipeng L


3

因为您可以在处理程序内部捕获ThreadAbortException和调用Thread.ResetAbort



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.