我创建了一个线程来执行某个方法。但有时即使线程仍在工作,我也想杀死这个线程。我该怎么办?我尝试了Thread.Abort(),但它会弹出一个消息框显示“线程已中止”。我该怎么办?
我创建了一个线程来执行某个方法。但有时即使线程仍在工作,我也想杀死这个线程。我该怎么办?我尝试了Thread.Abort(),但它会弹出一个消息框显示“线程已中止”。我该怎么办?
Thread.Abort()
!Thread.Abort
很危险。相反,您应该与线程合作,以便可以平静地关闭它。线程需要设计成可以被告知自杀,例如通过设置一个布尔变量keepGoing
为false来停止线程。然后线程将会有类似于:
while (keepGoing)
{
/* Do work. */
}
如果线程可能会在Sleep
或Wait
中阻塞,那么可以通过调用Thread.Interrupt()
来打断它们。线程应该准备好处理ThreadInterruptedException
异常:
try
{
while (keepGoing)
{
/* Do work. */
}
}
catch (ThreadInterruptedException exception)
{
/* Clean up. */
}
select()
。 - Jonathon Reinhart你应该只在万不得已时才调用Abort()。相反,你可以使用一个变量来同步线程:
volatile bool shutdown = false;
void RunThread()
{
while (!shutdown)
{
...
}
}
void StopThread()
{
shutdown = true;
}
这允许您的线程干净地完成其工作,使您的应用程序处于已知良好状态。
private void RunThread()
{
while(!this.flag.WaitOne(TimeSpan.FromMilliseconds(100)))
{
// ...
}
}
这里的this.flag
是ManualResetEvent的实例。这意味着你可以在线程外部调用this.flag.Set()
来停止循环。
当标志被设置时,WaitOne方法才会返回true。否则,它将在指定的超时时间(例如100毫秒)后超时,线程将再次运行循环。
while (!WillTerminate) {..} HasTerminate.Set();
- mathkThread.Interrupt
来唤醒它。WaitHandle
类发送信号。我同意Jon 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( );
}
}
Thread
构造函数不理解异步委托。您可以在这里阅读有关此问题的内容(https://dev59.com/91cP5IYBdhLWcg3wd5um)或者在这里(https://dev59.com/oYrda4cB1Zd3GeqPM3vO)。因此,`_thread.Interrupt()` 将中断一个已经终止的线程,所以在实践中它将不起作用。 - Theodor Zouliasawait
点之后的代码将在与之前相同的线程上继续运行。在你的示例中,await Task.Delay(1)
是_thread
将要终止的地方,而随后的Thread.Sleep(FromMinutes(10))
将使一个ThreadPool
线程进入睡眠状态,而不是_thread
。然后,_thread.Interrupt();
将无法起任何作用。 - Theodor Zouliasawait
之前和之后记录Thread.CurrentThread.ManagedThreadId
并查看它是否相同,以此来验证。 - Theodor Zoulias