我创建了一个运行某种方法的线程。但有时我想杀死线程,即使它仍在工作。我怎样才能做到这一点?我尝试了Thread.Abort(),但它显示了一个消息框,说“线程已中止”。我该怎么办?
答案 0 :(得分:48)
Thread.Abort()
! Thread.Abort
很危险。相反,你应该与线程合作,以便它可以安静地关闭。需要设计线程,以便可以告诉它自杀,例如,当你想让线程停止时,你设置一个布尔keepGoing
标志。然后该线程将具有类似
while (keepGoing)
{
/* Do work. */
}
如果该帖子可能会在Sleep
或Wait
中阻止,那么您可以通过调用Thread.Interrupt()
将其从这些功能中删除。然后应该准备线程来处理ThreadInterruptedException
:
try
{
while (keepGoing)
{
/* Do work. */
}
}
catch (ThreadInterruptedException exception)
{
/* Clean up. */
}
答案 1 :(得分:25)
你应该只打电话给Abort()作为最后的手段。您可以使用变量来同步此线程:
volatile bool shutdown = false;
void RunThread()
{
while (!shutdown)
{
...
}
}
void StopThread()
{
shutdown = true;
}
这允许你的线程干净地完成它正在做的事情,让你的应用程序处于一个已知的良好状态。
答案 2 :(得分:9)
最正确且线程安全的方法是使用WaitHandle在线程停止时向线程发出信号。我主要使用ManualResetEvent。
在你的主题中,你可以:
private void RunThread()
{
while(!this.flag.WaitOne(TimeSpan.FromMilliseconds(100)))
{
// ...
}
}
其中this.flag
是ManualResetEvent的一个实例。这意味着您可以从线程外部调用this.flag.Set()
来停止循环。
WaitOne方法仅在设置标志时返回true。否则,它将在指定的超时(示例中为100毫秒)后超时,并且线程将再次运行循环。
答案 3 :(得分:7)
杀死一个帖子不是一个好主意。最好发出信号表示它应该停止并让它优雅地结束。有各种不同的方法可以做到这一点。
Thread.Interrupt
戳它。WaitHandle
类发送信号。我没有必要重新讨论每种方法的使用方法,因为我已经在this answer中这样做了。
答案 4 :(得分:2)
中止一个帖子是一个非常糟糕的主意,因为在中止时你无法确定线程正在做什么。
相反,拥有一个线程可以检查的属性,以及您的外部代码可以设置的属性。让线程在安全的地方退出时检查这个布尔属性。
答案 5 :(得分:2)
我同意Jon B
volatile bool shutdown = false;
void RunThread()
{
try
{
while (!shutdown)
{
/* Do work. */
}
}
catch (ThreadAbortException exception)
{
/* Clean up. */
}
}
void StopThread()
{
shutdown = true;
}
答案 6 :(得分:1)
还有我的WebServer类中杀死线程的例子......
https://net7ntcip.codeplex.com/SourceControl/changeset/view/89621#1752948
我想说Abort是可以的,只要了解后果是什么......只要你在长时间运行任务之前指示状态Abort会工作但是需要标志,如(ShouldStop或ActionBranch等)
查看示例!
答案 7 :(得分:0)
编辑:
我为此创建了一个小类
注意到它不适用于 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( );
}
}