2016-05-31 5 views
1

ユーザーがAbortを呼び出したが、プログラムが終了しているために、現在実行中のスレッドが途中で中止されているかどうかを示すイベントはありますか?プログラムが終了しているためにスレッドが中止されているかどうかを知る方法はありますか?

私はすべてのスレッドがスレッドIDに関する情報とともにシャットダウンするたびに、これを必要とします。

私はそれがAppDomainUnloadイベントになることを期待していましたが、the documentationはそれについてnilchと言います。

This page on the MSDNは言う:

ランタイムは、プロセスがシャットダウンしているため、バックグラウンドスレッドを停止し、例外がスレッドでスローされません。ただし、AppDomain.Unloadメソッドがアプリケーションドメインをアンロードするためにスレッドが停止すると、ThreadAbortExceptionがフォアグラウンドスレッドとバックグラウンドスレッドの両方でスローされます。

実際にテストするには、長時間実行している2つのスレッド(最初はフォアグラウンドスレッド、もう1つはバックグラウンドスレッド)を作成し、すぐに現在のプロセスを終了してアンロードしようとする小さなプログラムを書きました現在のappdomain。

これは、DomainUnloadハンドラを呼び出すだけでなく、実行中の2つのスレッドを中止しようと試みて、ThreadAbortExceptionを送信する必要があります。

しかし、それは起こりません。

出力ウィンドウには、次の出力が表示されます。ここでは

[#10] [Foreground]Starting to do stuff. 
The thread 0x183c has exited with code 0 (0x0). 
[#9] [Worker]Starting to do stuff. 
[#10] [Foreground]Slept for 5 seconds. Now finishing up the doing of stuff. 
The thread 0x2954 has exited with code 0 (0x0). 
The program '[11224] KnowAboutDyingThread.vshost.exe' has exited with code 0 (0x0). 

は私のコードです:

using System; 
using System.Diagnostics; 
using System.Threading; 

namespace KnowAboutDyingThread 
{ 
    // Source: https://msdn.microsoft.com/en-us/library/h339syd0%28v=vs.110%29.aspx 
    // When the runtime stops a background thread because the process is shutting down, 
    // no exception is thrown in the thread. However, when threads are stopped because the 
    // AppDomain.Unload method unloads the application domain, a ThreadAbortException is 
    // thrown in both foreground and background threads. 

    // I am trying that out 
    // I asked a question here about it: http://stackoverflow.com/questions/37552668/is-there-a-way-to-know-if-a-thread-is-being-aborted-because-the-program-is-termi 
    // Permalink: http://stackoverflow.com/q/37552668/303685 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      AppDomain.CurrentDomain.DomainUnload += CurrentDomain_DomainUnload; 
      ThreadPool.QueueUserWorkItem(Do); 
      var t = new Thread(Do); 
      t.Name = "Foreground"; 
      t.Start(); 

      Process.GetCurrentProcess().Close(); 
     } 

     private static void CurrentDomain_DomainUnload(object sender, EventArgs e) 
     { 
      Debug.Print("Unloading current appdomain..."); 
     } 

     static void Do(object state) 
     { 
      try 
      { 
       Debug.Print(string.Format($"[#{Thread.CurrentThread.ManagedThreadId}] [{Thread.CurrentThread.Name ?? "Worker"}]Starting to do stuff.")); 
       Thread.Sleep(5000); 
       Debug.Print(string.Format($"[#{Thread.CurrentThread.ManagedThreadId}] [{Thread.CurrentThread.Name ?? "Worker"}]Slept for 5 seconds. Now finishing up the doing of stuff.")); 
      } 
      catch(ThreadAbortException abort) 
      { 
       Debug.Print(string.Format($"[#{Thread.CurrentThread.ManagedThreadId}] [{Thread.CurrentThread.Name ?? "Worker"}]Do got ThreadAbortException: {abort.GetType().Name}: {abort.Message}")); 
      } 
      catch(Exception ex) 
      { 
       Debug.Print(string.Format($"[#{Thread.CurrentThread.ManagedThreadId}] [{Thread.CurrentThread.Name ?? "Worker"}]Do had an exception: {ex.GetType().Name}: {ex.Message}")); 
      } 
     } 
    } 
} 





    [1]: https://msdn.microsoft.com/en-us/library/system.appdomain.domainunload%28v=vs.110%29.aspx 
+0

'Thread.Abort'を実行しないでください。あなたが使っているものが何であれ、あなたは間違ったアプローチを取っています。 'Thread.Abort'は悪です。あなたは "Thread.Abort'を呼び出さずに私のプログラムをどのように終了させるのですか?もう一度、['Thread.Abort'は悪です。](http://stackoverflow.com/questions/3632149/question-about-terminating-a-thread-cleanly-in-net) – spender

+0

私は病気をよく知っています'Thread.Abort'と' Thread.Interrupt'を使っているのですが、私の質問はこれらのメソッドを使うことの副作用とはほとんど関係がありません。 –

+1

あなたはあなたが望む動作を得るために 'Process.GetCurrentProcess()。Kill();'をする必要があると思います。 'Close()'を実行すると正常にシャットダウンしますが、forgroundスレッドの 'Do'はクローズメッセージを監視する方法がないため、プロセスを起動しません。そして、それでもなお、「DomainUnload」は強制終了されてもまだ起動しないかもしれませんが、少なくとも「終了しました....」セクションは表示されません。 –

答えて

0

バックグラウンドスレッドが正常に終了することになっていません。

非同期例外をキャッチすることはできません。これはフォアグランドスレッドにも当てはまります。

フォアグラウンドスレッドでは、ブロックfinallyに正常に入ることができますが、キャッチブロックは正常に入ることはできません。

あなたはおそらく確定オブジェクトを使用している行うことができます最も簡単な方法:

using System; 
using System.Diagnostics; 
using System.Threading; 

namespace ReliableStop 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Debug.WriteLine("-- Started Main. Thread: {0}", Thread.CurrentThread.ManagedThreadId); 

      var everStarted = new ManualResetEvent(false); 

      var t = new Thread(o => 
      { 
       Debug.WriteLine("-- Thread entered here."); 
       everStarted.Set(); 

       using (new PostMortemThreadDump()) 
       { 
        try 
        { 
         Thread.Sleep(100); 
        } 
        catch 
        { 
         Debug.WriteLine("-- Attempt to catch everything."); 
        } 
        finally 
        { 
         Debug.WriteLine("-- Attempt to process finally."); 
        }      
       } 
      }); 
      t.IsBackground = true; 
      t.Start(); 

      // Check that the thread has started. 
      everStarted.WaitOne(); 

      // ... Good bye, no need to kill, I will die on my own. 
     } 
    } 

    class PostMortemThreadDump : IDisposable 
    { 
     int threadId { get; } 
     public PostMortemThreadDump() 
     { 
      threadId = Thread.CurrentThread.ManagedThreadId; 
     } 

     ~PostMortemThreadDump() 
     { 
      Dispose(false); 
     } 

     void Dispose(bool disposing) 
     { 
      if (disposing) 
      { 
       Debug.WriteLine("-- PostMortemThreadDump. Finished normally."); 
      } 
      else 
      { 
       Debug.WriteLine("-- PostMortemThreadDump. Thread: {0}", threadId); 
      } 
     } 

     public void Dispose() 
     { 
      Dispose(true); 
      GC.SuppressFinalize(this); 
     } 
    } 
} 

出力:あなたはフォアグラウンドスレッドを使用するように変更した場合今

-- Started Main. Thread: 9 
-- Thread entered here. 
The thread 0x6fc8 has exited with code 0 (0x0). 
The thread 0x12b4 has exited with code 0 (0x0). 
-- PostMortemThreadDump. Thread: 10 
The program '[25260] ReliableStop.vshost.exe' has exited with code 0 (0x0). 

、あなたはまた、 `最終的に実行ブロックを取得します:あなたが見ることができるように

-- Started Main. Thread: 9 
-- Thread entered here. 
The thread 0x4d54 has exited with code 0 (0x0). 
The thread 0x20c8 has exited with code 0 (0x0). 
-- Attempt to process finally. 
-- PostMortemThreadDump. Finished normally. 
The thread 0x6928 has exited with code 0 (0x0). 
The program '[26328] ReliableStop.vshost.exe' has exited with code 0 (0x0). 

、ファイナライザは、両方のケースで実行され、前面にありますあなたはブロックfinallyを実行します。

Process.GetCurrentProcess().Close()を呼び出すことは、このシナリオには影響しません。

関連する問題