如何在C#中立即终止一个线程?

52

我正在使用thread.Abort方法来终止线程,但它没有生效。是否有其他终止线程的方法?

private void button1_Click(object sender, EventArgs e)
{
    if (Receiver.IsAlive == true)
    {
        MessageBox.Show("Alive");
        Receiver.Abort();
    }
    else
    {
        MessageBox.Show("Dead");
        Receiver.Start();
    }
}

我正在使用这个,但每次我得到Alive状态时,Receiver是我的全局线程。


13
危险,威尔·罗宾逊,危险!使用Thread.Abort应该非常谨慎——几乎总是一个坏主意。 - Marc Gravell
4
那么应该使用什么来终止线程? - Mobin
4
请要求该线程停止,并从那一刻开始忽略该线程。 - MSalters
17
如果你必须将一个运行任意、潜在敌对的代码的线程降级,那么唯一相对安全和有效的方法是将该线程隔离到自己的进程中。无法保证终止线程一定成功,但你应该能够结束一个进程。 - Eric Lippert
1
为了补充这个(旧)问题的评论,这里有一个相关的(旧)问题:“使用Thread.Abort()有什么问题”。 - Wai Ha Lee
简单来说,Abort 不起作用。 - Toolkit
5个回答

77

要终止一个线程很困难的原因是语言设计者希望避免以下问题:你的线程获取了一个锁,然后在它释放锁之前被杀死。现在需要该锁的任何人都会被卡住。

你必须使用一些全局变量来告诉线程停止运行。你必须在线程代码中手动检查该全局变量,如果看到它指示应停止,则返回。


我自己使用这个机制。对于基于UI的代码,我设置一个全局变量;对于服务,我检查一个数据库表。简单易懂、可预测。 - Ed Power
6
如果可能的话,使用ManualResetEvent而不是变量,因为它们就是为此设计的。 - Steve Sheldon
3
我现在很好奇——手动重置事件如何比其他方法更好地检查提前终止条件?我知道当我们需要在某些情况下阻塞时它们更好用,但是在这里没有阻塞。 - redtuna
基本上我同意,但在非常特定的情况下(您有一个线程不需要与其他线程同步-然后您可以检查我的解决方案)。 - Nickon
我更喜欢Adrian Regan的答案,其中包括告诉线程应该停止(interrupt)的代码,如果线程在约定的时间内无法停止,则最终采用abort - ToolmakerSteve

34

你可以用那种方式立即杀死对手:

private Thread _myThread = new Thread(SomeThreadMethod);

private void SomeThreadMethod()
{
   // do whatever you want
}

[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
private void KillTheThread()
{
   _myThread.Abort();
}

我一直使用它,对我很有效:)


但请参见https://dev59.com/_HI_5IYBdhLWcg3wBuT3#1560567,以及其他描述为什么thread.abort是有风险的答案。 - ToolmakerSteve
2
Adrian Regan的回答是一种更安全的使用Abort的方式 - 作为最后的手段,用于终止一个线程无法结束的情况。 - ToolmakerSteve
不,它不会终止线程,你可以用“do while”测试一下。 - Toolkit

24

你应该首先确定一些终止线程的协议。例如,一个running_变量,线程可以检查并遵守。

你的主线程代码应该被包装在一个异常块中,捕获ThreadInterruptException和ThreadAbortException,以便在退出时可以干净地清理线程。

在ThreadInterruptException的情况下,你可以检查running_变量来判断是否应该继续执行。在ThreadAbortException的情况下,你应该立即清理并退出线程过程。

试图停止线程的代码应该执行以下操作:

running_ = false;
threadInstance_.Interrupt();
if(!threadInstance_.Join(2000)) { // or an agreed resonable time
   threadInstance_.Abort();
}

4
在我的观点中,这是唯一可接受的答案。是的,你首先需要一个变量来记录线程何时可能退出,但如果你在线程内部阻塞,你可能永远没有机会检查那个变量。需要另一种中断被阻塞的线程的方法,而这个答案解决了我的问题。谢谢! - CramerTV
如果threadInstance_.Interrupt()能够快速结束线程,threadInstance_.Join将会抛出System.Threading.ThreadStateException: Thread has not been started异常。 - djk
我想知道是否可以在不实现CancellationToken的类似puppeteer-sharp的东西中使用Interrupt? - Toolkit
实际上,这并不起作用,threadInstance_ 仍在工作。 - Toolkit

9
线程在完成工作后将被终止,因此如果您正在使用循环或其他操作,应该向线程传递变量以停止循环。之后,线程将会结束。

6
C#的Thread.Abort不能保证立即终止线程。当一个线程对自身调用Abort时,可能会起作用,但当一个线程对另一个线程调用时,则不一定会立即终止。请参考文档:http://msdn.microsoft.com/en-us/library/ty8d3wta.aspx。我在编写与硬件交互的工具时遇到了这个问题,你想要立即停止,但不能保证立即终止。我通常使用一些标志或其他逻辑来防止在线程上运行的代码部分执行(我不希望在中止时执行 - 棘手)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接