2

私はこのコードスニペットを書きました:

        static void Main(string[] args)
    {
        Console.WriteLine("Start");

        Thread secondThread = new Thread(ThrowAnException);
        secondThread.Start();

        Console.ReadKey();
    }

    static void ThrowAnException()
    {
        throw new Exception("Second Thread Exception");
    }
}

私の理解では、例外が2番目のスレッドで発生すると、例外はスレッドのスタックを下に移動し、未処理の場合、子スレッドはサイレントに終了します。私が見ているのは、スレッドがメインスレッドに割り込んでおり、ThrowAnException メソッドで「Exception was Unhandled」で中断していることです。

デバッグありとなしの両方で実行しましたが、動作は同じです。

私が間違っていることはありますか?

4

4 に答える 4

7

.NET 2.0 以降、未処理の例外はプログラムを終了させます。メインスレッドが「中断」されると考えるのは正しい考え方ではありません。プログラム全体が中止され、すべてのスレッドが停止します。これは Thread.Abort() の「失礼な」バージョンであり、停止することはできません。

AppDomain.UnhandledException イベントを通じて最後のあえぎがあります。e.UnhandledException.ToString() の値をログに記録する機会を与えるために起動されるため、クラッシュを診断することができます。見落とされがちですが、プログラムが暴走し、ユーザーとそのマシンが、あなたが思いもよらなかった非常に驚くべき方法であなたのプログラムを扱った場合のクラッシュに対処するために不可欠です。

デフォルトの CLR ポリシーをオーバーライドする .config ファイルの属性を使用して、プログラムをクラッシュさせないようにすることは実際には可能です。しかし、その方法は狂気であり、ジョブを終了せずに終了するスレッドは、プログラムを完全に診断できない方法で誤動作させるだけです。.NET 1.x で試してみましたが、悪い考えとして却下されました。

于 2013-06-21T16:45:48.893 に答える
1

あなたが見ているのは正しい行動です。ユーザーが開始したスレッドで未処理の例外が発生すると、プログラムがクラッシュします。

the child thread terminates silently

おそらく、あなたが説明したのは.NET 1.xの古代からのものかもしれません。これは、.NET 2.0 以降では当てはまりません。

とはいえ、スレッドがプログラムをクラッシュさせないようにする方法はいくつかあります。(これはデモ用であり、練習用ではありません。絶対に行わないでください)。

  Action a = ThrowAnException;
  a.BeginInvoke(null, null);

これによりThrowAnException、APM を使用して ThreadPool スレッドで呼び出されます。を呼び出すまで、例外は表示されませんEndInvoke。ただし、APM は非同期を行うための推奨される方法ではなくなりました。

C# 4.0 Task Parallel Library と C# 5.0 async/await を見て、.NET/C# の優れた点を確認してください。

于 2013-06-21T16:25:50.817 に答える
0

あなたの理解はほぼ正しいです。

スレッド内の未処理の例外 ( を除くThreadAbortException) は、呼び出しスタックを効果的に破壊します。その後、スレッドは黙って強制終了されます。しかし、災害はそれだけではありません。その後、例外は実行中のプロセス全体を消費します。ただし、プロセスが強制終了される直前に、AppDomain.UnhandledExceptionイベントが発生します。例外をログに記録する (または大きな申し訳ありませんがメッセージを表示する) 機会を提供します。のisTerminatingプロパティUnhanledExceptionEventArgsは常にtrueです。

注意すべきことは、dot-net ではスレッド間に親子関係がないことです。すべてのスレッドは同等です。スレッドの下にあるのは AppDomain 自体だけです。

あなたが見たことを説明するために、2番目のスレッド(子スレッドではない)の例外は、最初のスレッドを中断したり、影響を与えたりしませんでした。2 番目のスレッドは強制終了されます。その後、プロセス全体が強制終了されます。プロセスが強制終了されると、最初のスレッドには隠れる場所がありません。それは死ぬ運命にある。catchコードが Visual Studio 内で実行されている場合 (デバッガーが接続されている場合)、デバッガーは例外をキャッチするブロックがないことを認識するとすぐに例外をキャッチできます。それは、メインスレッドで壊れているのを見るときです。デバッガーはメイン スレッドを中断するだけでなく、例外が発生したスレッドを含むすべてのスレッドを中断しています。コードを変更して再開する機会が与えられます。

デバッガーがないと、例外は独自のスレッドを消費し、プロセス全体を消費します。

于 2013-06-21T16:20:27.933 に答える