C#スレッドの終了とThread.Abort()


85

MSDNでは、Thread.Abort()メソッドの説明に次のように記載されています。「このメソッドを呼び出すと、通常はスレッドが終了します。」

なぜいつもではないのですか?

どちらの場合、スレッドは終了しませんか?

スレッドを終了する他の可能性はありますか?

回答:


60

Thread.Abort()ThreadAbortExceptionスレッドにを注入します。スレッドは、を呼び出すことによって要求をキャンセルできThread.ResetAbort()ます。また、finally例外が処理される前に実行されるブロックなど、特定のコード部分があります。何らかの理由でスレッドがそのようなブロックでスタックしている場合、例外がスレッドで発生することはありません。

呼び出し元は、呼び出し時にスレッドの状態をほとんど制御Abort()できないため、通常、そうすることはお勧めできません。代わりに、終了を要求するメッセージをスレッドに渡します。


どんなメッセージ?メソッド呼び出しを意味しますか?
user101375 2010

4
これは、スレッド間でデータを渡す方法によって異なります。たとえば、スレッドがタスクキューを持つワーカースレッドである場合、PleaseTerminateメッセージをキューに入れて、スレッドに適切に処理させることができます。
ブライアンラスムッセン

私のスレッドには、解決すべき大きな問題が1つあります。それは、タスクキューがないことです。
user101375 2010

私が言ったように、それはあなたのスレッドコードがどのように設計されているかに依存します。おそらく、メンバー変数を介してシグナルを送ることができます。利用可能な実際のコードがなければ、より具体的にすることは困難です。
ブライアンラスムッセン

54

どちらの場合、スレッドは終了しませんか?

この質問は重複しています。

Thread.Abort()の使用の何が問題になっていますか

スレッドを終了する他の可能性はありますか?

はい。あなたの問題は、丁寧に停止するように言うことができないスレッドを決して開始してはならず、それがタイムリーに停止することです。(1)停止するのが難しい、(2)バグがある、または最悪の場合(3)ユーザーに対して敵対的である可能性があるスレッドを開始する必要がある状況にある場合、正しいことは新しいプロセスで、新しいプロセスでスレッドを開始し、スレッドを停止するときにプロセスを終了します。非協調的なスレッドの安全な終了を保証できる唯一のことは、オペレーティングシステムがプロセス全体を停止することです。

詳細については、この質問に対する私の過度に長い回答を参照してください。

C#のループ内でlockステートメントを使用する

関連するビットは、スレッドを中止する前にスレッドが自殺するのをどのくらい待つ必要があるかに関する考慮事項について説明する最後のビットです。


エリック、スレッドが同期オブジェクトを待機している場合、スレッドに停止するように丁寧に指示するにはどうすればよいですか(例:EventWaitHandle.WaitOne();?
コービン2010年

5
@Corvin:1つのスレッドが別のスレッドと通信する方法を説明する2つのスレッド間の契約は、それらのスレッドで実行されるコードの作成者次第です。(1)スレッドXがオブジェクトを永久に待機する必要があり、(2)スレッドYが有限時間でスレッドXをクリーンにシャットダウンできる必要があるという要件がある場合、矛盾する要件があると思います。どちらが勝つかを決定します。前者の場合、スレッドYは待機する必要があります。後者の場合、スレッドXは永遠に待機するべきではなく、少しの間待機する必要があります。
Eric Lippert 2010年

回答ありがとうございます。次のアーキテクチャについて考えてみます。特定のシステム全体のイベントが発生したときに、それ自体を最小化する必要があるアプリケーションがあります。そのアプリケーションには、グローバルな名前付きイベントを待機し、そのイベントが設定されたときにその作業を行うスレッドがあります。一方、イベントが発生する前にアプリケーションを終了し、待機中のスレッドを閉じる必要がある場合があります。そのようなものをコーディングする侍の方法は何ですか?
コービン2010年

@Corvin:イベントを(短いタイムアウトで)待機し、待機の試行を停止する必要があるかどうかをチェックするループを作成できます(正常に終了できるようにするため)。このようにして、スレッドが停止する必要があることをスレッドに通知でき、スレッドが停止するまでタイムアウトするまで待つ必要があります。
Kevin Kibler 2010年

2
@Corvin、その待機中のスレッドをバックグラウンドスレッドにすると、アプリケーションが終了する前にそれを閉じる必要はありません。
ドンカークビー2010

17

なぜいつもではないのですか?どちらの場合、それはスレッドを終了しませんか?

手始めに、スレッドはをキャッチしてThreadAbortException、それ自体の終了をキャンセルする場合があります。または、中止しようとしている間、永遠にかかる計算を実行する可能性があります。このため、ランタイムは、要求した後にスレッドが常に終了することを保証できません。

ThreadAbortException もっとあります:

スレッドを破棄するためにAbortメソッドが呼び出されると、共通言語ランタイムはThreadAbortExceptionをスローします。ThreadAbortExceptionはキャッチできる特別な例外ですが、catchブロックの最後で自動的に再度発生します。この例外が発生すると、ランタイムはスレッドを終了する前にすべてのfinallyブロックを実行します。スレッドはfinallyブロックで無制限の計算を実行したりThread.ResetAbort()、中止をキャンセルするために呼び出したりできるため、スレッドが終了する保証はありません。

Abort()手動でスレッド化する必要はありません。スレッド内のメソッドを返すだけで、CLRがすべてのダーティな作業を実行します。これでスレッドは正常に終了します。


そのスレッドでメッセージループが開始されたため、Abort()する必要があります(Dispatcher.Run();)。正しく理解できたら、returnを呼び出すメソッドをスレッドに呼び出して終了する必要がありますか?
user101375 2010

7

FileStream.Read()現在何も受信していない名前付きパイプ(着信データの待機中に呼び出しブロックを読み取る)は、に応答しませんThread.Abort()Read()通話中に残ります。


6

スレッドがロックを保持していて、中止/強制終了された場合はどうなりますか?リソースがスタックしたまま

スレッドがそれ自体を中止するが、他のスレッドでは呼び出さない場合は正常に機能します。タスクを完了しておらず、リソースをクリーンアップする機会がない場合でも、影響を受けるスレッドを強制終了します。

参照MSDN


参照: マネージスレッドのベストプラクティス


5

ループでスタックしているスレッドを中止できないようです。

//immortal
Thread th1 = new Thread(() => { while (true) {}});

ただし、ループ中にスリープした場合はスレッドを中止できます。

//mortal
Thread th2 = new Thread(() => { while (true) { Thread.Sleep(1000); }});

1
これは正しくないようです。テストプログラムを実行しました: `{var th = new Thread(()=> {int i = 0; try {while(true){i ++;}} catch(Exception e){ Console.WriteLine( "aborting @ {0}"、i);}}); th.Start(); Thread.Sleep(1000); th.Abort(); th.Join(); }
WeipengL18年


3

ハンドラー内でをキャッチしThreadAbortExceptionて呼び出すことができるためですThread.ResetAbort



-1

スレッドがビジー状態でAbort()呼び出しを聞くことができない場合があります。これにより、通常、コードにThreadAbortingExceptionがスローされます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.