是否有一個事件會告訴我當前正在運行的線程是否在中途中止,而不是因爲用戶調用了Abort
而是因爲程序正在終止?有沒有辦法知道一個線程是否因程序終止而中止?
我需要爲每個線程關閉線程Id的信息。
我希望這將是AppDomainUnload
事件,但the documentation說不知道。
當運行時停止後臺線程,因爲進程正在關閉,也不例外在線程中拋出。但是,當線程由於AppDomain.Unload方法卸載應用程序域而停止時,ThreadAbortException會在前臺和後臺線程中拋出。
爲了測試這個事實,我編寫了這個小程序,它生成兩個長時間運行的線程,其中一個是前臺線程,另一個是後臺線程,並立即繼續退出當前進程,從而嘗試卸載當前的應用程序域。
這應該不僅調用DomainUnload
處理程序,而且還嘗試中止兩個正在運行的線程並向它們發送一個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
不要'Thread.Abort'。無論你使用什麼,你都會採取錯誤的做法。 'Thread.Abort'是邪惡的。你應該問「如何在不調用'Thread.Abort'的情況下終止我的程序」。再一次,['Thread.Abort'是邪惡的](http://stackoverflow.com/questions/3632149/question-about-terminating-a-thread-cleanly-in-net) – spender
我很清楚這個問題使用'Thread.Abort'和'Thread.Interrupt',我的問題與使用這些方法的副作用無關。 –
我想你需要做'Process.GetCurrentProcess()。Kill();'來獲得你想要的行爲。執行'Close()'會觸發正常的關閉,但forground線程上的'Do'沒有辦法監視關閉消息,因此不會觸發進程。即使如此,'DomainUnload'仍然可能因爲強制終止而無法啓動,但至少您可能無法獲得「正在完成...」部分。 –