.NET线程:如何在未启动的线程上捕获中止?

时间:2011-01-03 20:25:02

标签: c# .net multithreading thread-abort

编辑:这似乎是一个棘手的问题,所以我会把它弄清楚:

我没有用它来进行同步。当不再需要/需要时,只需杀死长时间运行的任务 假设:假设这些线程只是写入控制台(例如:“线程1”),睡眠随机长度,然后退出。如果它们被中止,我希望它们通过另一个控制台写入通知我(例如:“线程1中止”)。我希望能够将直接跳转到中止代码,如果我试图在它运行之前中止它,而没有任何机会执行它的正常功能。如果它在正常运行期间中止,它当然会打印两者。


我希望按顺序运行一大堆线程,在运行带有Visual Studio 2008的.NET 2.0的ASP站点上(不知道有多重要,但它确实存在),并且它们可能已经中止 - 清理应该运行的代码,无论它们的任务有多远。所以我做了一个这样的线程:

Thread t = new Thread(delegate() {
   try { 
      /* do things */ 
      System.Diagnostics.Debug.WriteLine("try");
   }
   catch (ThreadAbortException) {
      /* cleanup */ 
      System.Diagnostics.Debug.WriteLine("catch");
   }
});

现在,如果我希望中途停止一组线程,那么稍后可能仍需要进行清理。查看MSDN意味着您可以.Abort()一个尚未启动的线程,然后.Start()它,此时它将收到异常并正常执行。或者你可以.Join()中止线程等待它完成中止。大概你可以把它们结合起来。

  

http://msdn.microsoft.com/en-us/library/ty8d3wta(v=VS.80).aspx
  要等到线程中止,可以在调用Abort方法后调用线程上的Join方法,但不能保证等待将结束。
  如果在尚未启动的线程上调用Abort,则在调用Start时线程将中止。如果在被阻塞或正在休眠的线程上调用Abort,则线程被中断然后中止。

现在,当我调试并逐步执行此代码时:

t.Abort(); // ThreadState == Unstarted | AbortRequested
t.Start(); // throws ThreadStartException: "Thread failed to start."
// so I comment it out, and
t.Join(); // throws ThreadStateException: "Thread has not been started."

我没有看到任何输出,也没有在try或catch块上找到任何断点 奇怪的是,ThreadStartException未被列为.Start()的可能抛出,从这里:http://msdn.microsoft.com/en-us/library/a9fyxz7d(v=VS.80).aspx(或任何其他版本)

我理解这可以通过一个start参数来避免,该参数指出线程是否应该跳转到清理代码,并在Abort调用之前(这可能就是我要做的)。我可以 .Start()线程,然后.Abort()它。但是,由于不确定的时间可能会在.Start和.Abort之间传递,我认为它不可靠,文档似乎说我的原始方法应该有效。

我错过了什么吗?文档错了吗?

编辑:ow。并且你不能在非参数化的线程(开始)上调用.Start(param)。有没有办法找出一个线程是否参数化,除了试验和错误?我看到私人m_Delegate,但没有公开...

2 个答案:

答案 0 :(得分:3)

使用时......

t.Abort();
t.Start();

... ThreadStartExcpetion的innerException将包含ThreadAbortExeption,正如msdn所述:( 如果在尚未启动的线程上调用Abort,则线程将在调用Start时中止

如果你执行......

t.Start();
t.Abort();

... ThreadAbortException可能永远不会发生,因为线程在中止之前没有时间启动。

如果您测试类似......

t.Start();
Thread.Sleep(100);
t.Abort();

...应始终执行“清理”代码。

如果您需要执行清理代码,即使Thread尚未开始执行任何操作,可能的解决方案是与Abort调用一起启动清理方法。

此外,您应该尽量避免中止线程并使用不同的技术(http://msdn.microsoft.com/en-us/library/ms228964.aspx)

答案 1 :(得分:0)

我意识到文档暗示了什么,但事实并非如此。如果你中止一个线程然后启动它,它将永远不会以任何方式执行。 CLR非常聪明,知道线程中止是一项不稳定的业务,因此不能错过完全跳过线程执行的机会。

也许将你的清理代码变成子程序。如果父线程中止或知道中止,它将显式调用清理代码。

请记住.net在中止线程后“清理”的概念是卸载正在执行中止线程的程序集的appdomain。这是另一种说法“不要指望这种方式能够很好地清理”。您应该首先寻求不需要中止线程的设计。