我正在阅读一本关于c#开发的一般书,我来到线程中止部分。
这本书说明了当你在另一个线程上调用Thread.Abort()时,该线程会抛出一个ThreadAbortException,即使你试图压制它也会自动重新抛出它,除非你做了一些bs一般不赞成。这是提供的简单示例。
using System;
using System.Threading;
public class EntryPoint
{
private static void ThreadFunc()
{
ulong counter = 0;
while (true)
{
try
{
Console.WriteLine("{0}", counter++);
}
catch (ThreadAbortException)
{
// Attempt to swallow the exception and continue.
Console.WriteLine("Abort!");
}
}
}
static void Main()
{
try
{
Thread newThread = new Thread(new ThreadStart(EntryPoint.ThreadFunc));
newThread.Start();
Thread.Sleep(2000);
// Abort the thread.
newThread.Abort();
// Wait for thread to finish.
newThread.Join();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
这本书说:
当您的线程完成处理中止异常时,运行时会在异常处理程序的末尾隐式重新生成它。就像你自己重新抛出异常一样。因此,任何外部异常处理程序或finally块仍将正常执行。在该示例中,对Join的调用将不会像最初预期的那样永远等待。
所以我在Thread.Abort()调用周围包装了一个try catch并设置了一个断点,期望它达到这一点,考虑到文本说“任何外部异常处理程序或最终块仍将正常执行”。但它没有。我绞尽脑汁想出原因。
任何人都有任何想法为什么不是这种情况?这本书错了吗?
提前致谢。
答案 0 :(得分:8)
在中止的线程上抛出异常。一旦抛出异常就会向该线程的调用堆栈移动,但它不会跳转到另一个线程,也不会跳转到Thread.Abort
的调用者。
索赔是:
因此,任何外部异常处理程序或finally块仍将正常执行。
对此声明的更好测试是以下代码:
private static void ThreadFunc()
{
ulong counter = 0;
while (true)
{
try
{
try
{
Console.WriteLine("{0}", counter++);
}
catch (ThreadAbortException)
{
// Attempt to swallow the exception and continue.
Console.WriteLine("Abort!");
}
}
catch (ThreadAbortException)
{
Console.WriteLine("Do we get here?");
}
}
}
如果ThreadAbortException
是正常类型的异常,我们就不会指望"Do we get here?"
行,但我们会这样做。
答案 1 :(得分:1)
Thread.Abort()不会抛出异常。相反,线程中会抛出异常,即使您捕获它,也会立即重新抛出。在你的情况下,它会在打印“Abort!”之后立即重新出现。继续将你的线程方法的主体包装在另一个try / catch中,你将能够确认这一点。
答案 2 :(得分:1)
你可能会眨眼睛看得太快。像这样修改你的代码:
// Wait for thread to finish.
newThread.Join();
Console.ReadLine();
可能的输出:
....
8807
8808
Abort!
答案 3 :(得分:1)
那本书应该说的是你永远不应该使用Thread.Abort
,因为它有很多问题。
因此,您看到的任何非显而易见或意外的行为都应被视为您不应该使用Thread.Abort
。
Thread.Abort
的意思是向一个线程发出信号,表明应用程序正在终止,你未能很好地退出(我已经问过),现在你必须死掉。对此感到抱歉,但就是这样。
就是这样。您可以想到的所有其他用例都涉及到Thread.Abort应该有一个不同的解决方案,周期。
合作方法通常是最好的方法。使用信号(即使是像易失性布尔字段那样简单的东西),只需在线程退出时设置信号即可。在另一个线程中定期检查此信号,设置后退出。或者......如果您检测到信号,甚至会抛出异常。
从不使用Thread.Abort
从外部强加该异常。
现在,如果你真的想知道如何处理这个异常,你可以向运行时发出信号,告诉你不希望异常通过调用自动向上传播(ThreadAbortException是一种特殊情况) Thread.ResetAbort()
但是,你不应该这样做。
答案 4 :(得分:0)
当你启动线程时,你的代码继续运行,你启动的线程是单独运行的,也就是为什么我们不应该期望在main中命中该行。
using System;
using System.Threading;
public class EntryPoint
{
private static void ThreadFunc()
{
try
{
ulong counter = 0;
while (true)
{
try
{
Console.WriteLine("{0}", counter++);
}
catch (ThreadAbortException)
{
// Attempt to swallow the exception and continue.
Console.WriteLine("Abort!");
}
}
}
catch(ThreadAbortException)
{
Console.WriteLine("Certainly unstoppable!");
}
}
static void Main()
{
try
{
Thread newThread = new Thread(new ThreadStart(EntryPoint.ThreadFunc));
newThread.Start();
Thread.Sleep(2000);
// Abort the thread.
newThread.Abort();
// Wait for thread to finish.
newThread.Join();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
记住ThreadAbortException是一个v。特殊异常,因为出于所有目的,该线程意味着死亡。当你绝对终止你的应用并且线程中没有任何特殊内容时,这很好。如果您希望正常终止操作,请不要使用Thread.Abort ,使用单独的机制来告诉它需要停止的线程。就像在示例中一样,设置一个静态成员,它会检查while,下一个周期它知道它必须在受控制的地方停止。