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 ) );
}

さて、これをしばらく実行して、それがまだ機能するかどうか教えてください。

この問題は、コードがsleep-callを離れ、using-blockの暗黙のfinally-block内にあり、ストリームを閉じようとしているときに発生し、その後中止します。

の問題は、例外をスローすることを想定していないコード内であっても、どこでもThread.Abort発生する可能性があることです。

たとえば、if-expressionが評価された、-callが完了する前に、次のコードがクラッシュすることを本当に期待していますか?Dispose

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

呼び出しの直後に発生した場合はどうなり.Disposeますか?フィールドには引き続きnull以外の値が含まれるため、他の場所で微妙な問題が発生する可能性があります。

これを行うとどうなりますか:

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

このコードを使用すると、値を取得してnullに置き換え、Disposeの呼び出しに取り掛かる前にThreadAbortException、オブジェクトをそのままにしておくことができます。

ポイントを家に帰らせてください:

プログラムを終了する(またはスレッドが実行されているカスタムAppDomainを破棄する)必要があるシナリオを除いて、Thread.Abortは使用しないでください。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 に答える