我创建了一个运行某种方法的线程。但有时我想杀死线程,即使它仍在工作。我怎样才能做到这一点?我尝试了 Thread.Abort() 但它显示了一个消息框,上面写着“线程中止”。我应该怎么办?
8 回答
不要打电话Thread.Abort()
!
Thread.Abort
很危险。相反,您应该与线程合作,以便可以和平地关闭它。需要对线程进行设计,以便可以告诉它杀死自己,例如,keepGoing
当您希望线程停止时,将布尔标志设置为 false。然后线程会有类似的东西
while (keepGoing)
{
/* Do work. */
}
如果线程可能在 a 中阻塞,Sleep
那么Wait
您可以通过调用将其从这些函数中分离出来Thread.Interrupt()
。然后应该准备处理线程ThreadInterruptedException
:
try
{
while (keepGoing)
{
/* Do work. */
}
}
catch (ThreadInterruptedException exception)
{
/* Clean up. */
}
你真的应该只调用 Abort() 作为最后的手段。您可以使用变量来同步此线程:
volatile bool shutdown = false;
void RunThread()
{
while (!shutdown)
{
...
}
}
void StopThread()
{
shutdown = true;
}
这允许你的线程干净地完成它正在做的事情,让你的应用程序处于已知的良好状态。
最正确和线程安全的方法是使用 WaitHandle 在应该停止时向线程发出信号。我主要使用 ManualResetEvent。
在您的线程中,您可以拥有:
private void RunThread()
{
while(!this.flag.WaitOne(TimeSpan.FromMilliseconds(100)))
{
// ...
}
}
其中this.flag
是 ManualResetEvent 的一个实例。这意味着您可以this.flag.Set()
从线程外部调用来停止循环。
WaitOne 方法仅在设置标志时返回 true。否则,它将在指定的超时(示例中为 100 毫秒)后超时,线程将再次运行循环。
杀死线程不是一个好主意。最好发出信号让它停止并让它优雅地结束。有多种不同的方法可以做到这一点。
Thread.Interrupt
如果它被阻止,请使用它来戳它。- 轮询标志变量。
- 使用
WaitHandle
类发送信号。
我没有必要重新讨论如何使用每种方法,因为我已经在这个答案中这样做了。
中止线程是一个非常糟糕的主意,因为您无法确定线程在中止时正在做什么。
相反,有一个线程可以检查的属性,并且您的外部代码可以设置。当线程在安全的地方退出时,让线程检查这个布尔属性。
我同意乔恩 B
volatile bool shutdown = false;
void RunThread()
{
try
{
while (!shutdown)
{
/* Do work. */
}
}
catch (ThreadAbortException exception)
{
/* Clean up. */
}
}
void StopThread()
{
shutdown = true;
}
在我的 WebServer 类中也有杀死线程的例子......
https://net7ntcip.codeplex.com/SourceControl/changeset/view/89621#1752948
我想说 Abort 没问题,只要了解后果是什么……只要您在长时间运行的任务 Abort 将起作用之前指示状态,但需要标志,例如(ShouldStop 或 ActionBranch 等)
查看示例!
编辑:
我为此创建了一个小类
注意到它不适用于 async/await
向班级发布了更新,然后 Theodor Zoulias(谢谢 :))让我知道这个想法是有缺陷的。
现在我正在重新发布原始课程(不适用于 async/await!)
var t = new StopAbleThread(isShutDown => { Console.WriteLine("a"); while (!isShutDown()) { Console.WriteLine("b"); Thread.Sleep(TimeSpan.FromMinutes(10)); } } ) { IsBackground = true }; t.Start( );
像这样停止线程:
t.Stop();
班上:
public class StopAbleThread
{
public bool IsBackground
{
set => _thread.IsBackground = value;
}
private readonly Thread _thread;
private volatile bool _shutdown;
public delegate bool IsShutDown( );
public delegate void CodeToRun( IsShutDown isShutDown );
public StopAbleThread( CodeToRun codeToRun )
{
_thread = new Thread( ( ) =>
{
try
{
codeToRun( _IsShutDown );
}
catch( ThreadInterruptedException )
{
//ignore
}
} );
}
private bool _IsShutDown( )
{
return _shutdown;
}
public void Start( )
{
_thread.Start( );
}
public void Stop( )
{
_shutdown = true;
_thread.Interrupt( );
}
}