.NET Thread.Abort再次

时间:2010-01-18 09:30:48

标签: .net multithreading abort

我想再谈谈Thread.Abort功能的安全性。我有兴趣有一些方法来中止我无法控制的操作,实际上并不想要,但我希望尽快释放我的线程,以防止线程口渴我的应用程序。

所以我写了一些测试代码,看看是否可以使用Thread.Abort并让中止线程清理资源。这是代码:

int threadRunCount = 0;
int threadAbortCount = 0;
int threadFinallyCount = 0;
int iterations = 0;

while( true )
{
 Thread t = new Thread( () =>
 {
  threadRunCount++;
  try
  {
   Thread.Sleep( Random.Next( 45, 55 ) );
  }
  catch( ThreadAbortException )
  {
   threadAbortCount++;
  }
  finally
  {
   threadFinallyCount++;
  }
 } );

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

 iterations++;
}

所以,到目前为止,这段代码工作了大约5分钟,而threadRunCount总是等于threadFinallythreadAbort的数量稍微低一些,因为有些线程完成时没有中止或最终可能会中止。

所以问题是,我会错过什么吗?

3 个答案:

答案 0 :(得分:4)

通过人为的测试,你可以证明什么。

您所证明的是,使用您为测试编写的代码Thread.Abort似乎工作正常。

但问题是,一旦你开始使用需要处理的东西,所有的希望都会消失。

例如,试试这段代码:

using (Stream stream = new FileStream(@"C:\Test.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None))
{
    Thread.Sleep( Random.Next( 45, 55 ) );
}

现在,运行一段时间并告诉我它是否仍然有效。

当代码离开你的睡眠调用时出现问题,并且在使用块的隐式finally块内,并且即将关闭你的流,然后你中止它。

Thread.Abort的问题在于它可能发生任何地方,即使在不应该抛出异常的代码中也是如此。

例如,您是否真的希望以下代码在评估if-expression之后崩溃,但之前 Dispose - 呼叫已经消失通过?

if (_ObjectToDispose != null)
{
    _ObjectToDispose.Dispose();
    _ObjectToDispose = null;
}

如果在拨打.Dispose之后发生了什么?该字段仍将具有非空值,这可能会导致其他地方出现细微问题。

如果你这样做怎么办:

IDisposable objectToDispose = Interlocked.Exchange(ref _ObjectToDispose, null);
if (objectToDispose != null)
    objectToDispose.Dispose();

使用此代码,您获取值,将其替换为null,然后在调用Dispose之前,您的ThreadAbortException会发生,这将离开对象。

让我把重点放在家里:

  

Thread.Abort应该永远不会使用,除非您需要终止程序(或拆除其中运行有线程的自定义AppDomain)。您应该从不调用Thread.Abort然后继续运行。

除非您需要在未来的日程安排中计划错误。在这种情况下,请继续使用Thread.Abort,因为我几乎可以保证您会遇到问题。

答案 1 :(得分:1)

使用线程中止是足够安全的。然而,正如其他人所提到的,线程中止可能不会立即中止。调用线程中止将在线程中引发ThreadAbortException。要清理资源,您可以捕获此异常并进行必要的清理。

static void Run()
{
  try 
  {
    while(someCondition)
    {
       ....
       ....
       ....
       if (someOtherCondition)
          throw new ThreadAbortException("Thread aborted");
    }
  }
  catch(ThreadAbortException e)
  {
    ...
    ... //clean up resources here.
    ...
  }
  finally
  {
    ...
  }  
}

答案 2 :(得分:-1)

使用Thread.Abort很好。但是,它并不总是立即中止。如果一个线程正在执行非托管代码,它将不会实际中止,直到它返回托管代码。