1

我想再谈谈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总是等于threadFinally并且threadAbort数量略少,因为一些线程在没有中止的情况下完成,或者最终可能被中止。

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

4

3 回答 3

4

通过人为的测试,您可以证明任何事情。

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

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

例如,试试这个代码:

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

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

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

问题Thread.Abort在于它可以在任何地方发生,甚至在不应该抛出异常的代码中。

例如,您是否真的希望以下代码在 if 表达式被求值之后但-callDispose完成之前崩溃?

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,因为我几乎可以保证您会遇到问题。

于 2010-01-18T10:40:48.837 回答
1

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

static void Run()
{
  try 
  {
    while(someCondition)
    {
       ....
       ....
       ....
       if (someOtherCondition)
          throw new ThreadAbortException("Thread aborted");
    }
  }
  catch(ThreadAbortException e)
  {
    ...
    ... //clean up resources here.
    ...
  }
  finally
  {
    ...
  }  
}
于 2010-01-18T10:03:40.377 回答
-1

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

于 2010-01-18T09:45:56.297 回答