実行中のプログラムの状態が破損する可能性があるため、スレッドの中断や中断は避けてください。たとえば、リソースに対してロックを保持しているスレッドを中止したとしたら、これらのロックは解放されません。
のスレッドが互いに共同操作できるようにする代わりにシグナリングメカニズムを使用することを検討し、そう例えば、ブロックし、優雅にブロック解除ハンドル:
private readonly AutoResetEvent ProcessEvent = new AutoResetEvent(false);
private readonly AutoResetEvent WakeEvent = new AutoResetEvent(false);
public void Do()
{
Thread th1 = new Thread(ProcessSomething);
th1.IsBackground = false;
th1.Start();
ProcessEvent.WaitOne();
Console.WriteLine("Processing started...");
Thread th2 = new Thread(() => WakeEvent.Set());
th2.Start();
th1.Join();
Console.WriteLine("Joined");
}
private void ProcessSomething()
{
try
{
Console.WriteLine("Processing...");
ProcessEvent.Set();
}
finally
{
WakeEvent.WaitOne();
Console.WriteLine("Woken up...");
}
}
更新
非常に興味深い低レベル問題。 Abort()
が文書化されていますが、Interrupt()
ははるかに少ないです。
あなたの質問に対する短い答えは、いいえ、Abort
またはInterrupt
を呼び出すことによってfinallyブロック内のスレッドを復帰させることはできません。
finallyブロックのスレッドを中止または中断できないのは設計通りです。最終的にブロックが期待どおりに実行できるように設計されています。 finallyブロックでスレッドを中止して中断することができれば、これはクリーンアップルーチンに予期しない結果をもたらす可能性があり、アプリケーションを破損した状態にしておくのは良いことです。
スレッドの割り込みにわずかなニュアンスがあるのは、スレッドがfinallyブロックに入る前のいつでも割り込みがスレッドに対して発行されている可能性がありますが、SleepWaitJoin
状態ではない(つまりブロックされていない)ことです。この例では、finallyブロックにブロッキング呼び出しがあった場合、即座にThreadInterruptedException
がスローされ、finallyブロックからクラッシュします。最後にブロック保護がこれを防ぎます。
finallyブロックでの保護と同様に、これはtryブロックおよびCER(Constrained Execution Region)にも拡張されています。これは、領域が実行されるまでスローされる範囲をユーザコードで設定することができます。 はでなければならず、遅延は中止されます。
と呼ばれるものは例外です。これらは、CLRホスティング環境自体によって提起された
ThreadAbortExceptions
です。これらはfinallyブロックとcatchブロックを終了させますが、
ではなく、 CERです。たとえば、CLRは、作業の終了に時間がかかりすぎると判断したスレッドに応答して、失礼なアボートを発生させることができます。 AppDomainをアンロードしようとしたとき、またはSQL Server CLR内でコードを実行しようとしたとき。特定の例では、アプリケーションがシャットダウンしてAppDomainがアンロードされると、AppDomainのアンロードタイムアウトが発生するため、CLRはスリープ中のスレッドに対してRude Abortを発行します。
finallyブロックでの中止と中断は、ユーザーコードでは起こりませんが、2つの場合の動作が少し異なります。
中止
finallyブロック内のスレッドにAbort
を呼び出し、呼び出し元のスレッドがブロックされています。これはdocumentedです:
中止されているスレッドが、そのようなcatchブロック、finallyブロック、または制約の実行領域として、コードの保護された領域内にある場合は中止がブロックされる可能性があります呼び出すスレッド。中止の場合
睡眠は無限ではなかった場合:
- それはここに停止し、すぐに進行せず、すなわち、呼び出し元のスレッドが
Abort
を出しますが、finallyブロックが終了するまでここにブロックします。 Join
ステートメントに転送します。
- calleeスレッドの状態は
AbortRequested
に設定されています。
- 被告人は眠っています。
- 呼び出し先がウェイクアップすると、状態が
AbortRequested
であるため、finallyブロックコードの実行を継続して終了します。つまり、終了します。
- abortedスレッドがfinallyブロックを離れると、例外は発生せず、finallyブロックの後のコードは実行されず、スレッドの状態は
Aborted
になります。
- 呼び出しスレッドはブロック解除され、
Join
ステートメントに進み、呼び出されたスレッドが終了するとすぐに渡されます。睡眠は無限ではなかった場合
だから無限の睡眠であなたの例を考えると、呼び出し元のスレッドは、割り込みの場合には、ステップ1
割り込み
で永遠にブロックします:
あまり説明されていません...
- 呼び出し元のスレッドが
Interrupt
を発行し、実行を継続していきます。
- 呼び出しスレッドは
Join
ステートメントでブロックされます。
- 呼び出し先スレッドは、次のブロッキング呼び出しで例外を発生するように設定されていますが、最終的にはブロックされているので、ブロックされていません。
- 被告人は眠っています。
- 呼び出し先が起動すると、finallyブロックの実行を継続します。
- 中断されたスレッドがfinallyブロックを離れると、次のブロック呼び出しで
ThreadInterruptedException
がスローされます(下記のコード例を参照)。
- 呼び出し元のスレッドが「ジョイン」と呼ばれ、スレッドが終了したように継続ステップ6で未処理の
ThreadInterruptedException
は今のプロセスを平坦化している、しかし、...
だからもう一度、無限の睡眠であなたの例を与えます呼び出し元のスレッドが永遠にブロックしますが、手順2
概要
でそうAbort
とInterrupt
が若干異なる振る舞いを持っているが、彼らは永遠に眠っていると呼ばれるスレッド結果、永遠のブロッキング呼び出し元のスレッド(の両方になりますあなたの例)。
ブロックされたスレッドがfinallyブロックを終了するように強制することができますが、これはCLRだけで発生する可能性があります。ThreadAbortException.ExceptionState
を反映させることもできません。内部CLR呼び出しによってAbortReason
- 簡単に悪になる機会はありません...)。
CLRは、ユーザーコードが最終的にブロックを早期に終了させないようにします。破損した状態を防ぐのに役立ちます。 Interrupt
と若干異なる行動の例
:私は質問への答えを知らない
internal class ThreadInterruptFinally
{
public static void Do()
{
Thread t = new Thread(ProcessSomething) { IsBackground = false };
t.Start();
Thread.Sleep(500);
t.Interrupt();
t.Join();
}
private static void ProcessSomething()
{
try
{
Console.WriteLine("processing");
}
finally
{
Thread.Sleep(2 * 1000);
}
Console.WriteLine("Exited finally...");
Thread.Sleep(0); //<-- ThreadInterruptedException
}
}
、私は*一般的なルールとして、私は( '割り込みを避けることを知っています* ) 'をスレッド間のシグナリングのメカニズムとして使用します。 –
Interrupt/Abortが最後に動作しなくなったとき、なぜMSDNがその逆を言っているのか、もっと詳しい説明やドキュメントを探していました。私の例は、より複雑なポーラータイプです。私は現在、それを提案した通りに読んでいます。 – Marek
スレッドアボートには2種類あります。フレンドリーな人はfinallyブロックのコードを中断しません。不合理なものは、IsBackgroundがtrueと等しいスレッド、または処理されない例外で終了するスレッドでプロセスがシャットダウンするときに呼び出されます。今や、コードが不当に中断されても問題ありません。 –