我有以下内容。
public static Thread testThread = new Thread(ThreadStart) {Name = "TestThread", IsBackground = true};
private void Form_Load()
{
testThread.Start()
}
private static void ThreadStart()
{
int count = 0;
try
{
while (true)
{
count++;
}
}
catch (Exception ex)
{
StreamWriter stream = new StreamWriter(File.OpenWrite("Exception.txt"));
stream.WriteLine(count + "\n" + ex);
stream.Flush();
stream.Close();
}
}
当我调用Thread.Abort()
时,我捕获异常并写出文件。
但是,如果我改为关闭应用程序,则不会写任何内容。
我也有
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
但它似乎没有抛出异常。
我想添加一个问题是谨慎的。
当父进程退出时,正在运行的后台线程会发生什么? 我的理解是抛出ThreadAbortException退出线程。 如果是这种情况,如何捕获ThreadAbortException以清除线程中可能存在的资源?
答案 0 :(得分:4)
首先,应用程序可能没有退出,因为你没有将它们变成后台线程。我的猜测是任务管理器会显示你的EXE意外运行的副本。在调用Start之前,需要在线程对象上将Thread.IsBackground设置为true。
其次,您期望的行为会被the documentation明确揭穿:
注意
当公共语言运行库(CLR)停止后台线程时, 在托管可执行文件中的所有前台线程结束后,它 不使用System.Threading.Thread.Abort。因此,你不能使用 ThreadAbortException用于检测何时存在后台线程 由CLR终止。
编辑:
当一个进程退出时,不需要清理工作线程持有的资源,因为,你知道,进程正在退出。关于后台线程的合同是它们可以在进程退出时随时被杀死。因此,如果您的后台线程正在执行需要事务正确性的操作,则它们可能不应该是后台线程。制作'em前台线程,让他们定期检查或等待重置事件,看看是否应该退出并允许进程结束。
答案 1 :(得分:4)
当CLR关闭进程时,它不会调用Thread.Abort或类似的东西。您的线程方法不会像main方法一样退出。
答案 2 :(得分:1)
如果您的主题的IsBackground
属性为false
,那么即使应用程序的主窗口关闭,您的主题仍会保持活动状态。
控制后台线程生命周期的最佳方法是创建sentinels,通常实现为volatile bool
字段,线程中的代码定期检查(例如,在每次迭代时) 。当sentinel指示应用程序正在终止时,线程应该停止执行。
以下代码显示了使用sentinel在200毫秒后终止线程:
public static Thread testThread = new Thread(ThreadStart)
{
Name = "TestThread",
IsBackground = false // Allow thread to terminate naturally
};
private static volatile bool isTerminating = false; // Sentinel
private void Form_Load()
{
testThread.Start();
Thread.Sleep(200); // Sleep 200 milliseconds
isTerminating = true; // Set sentinel to terminate thread
}
private static void ThreadStart()
{
int count = 0;
while (!isTerminating) // Keep looping until sentinel is set
count++;
using (StreamWriter stream = new StreamWriter(File.OpenWrite("Result.txt")))
{
stream.WriteLine(count);
stream.Flush();
}
}
编辑:要回答您的上一个问题,“为了清理线程中可能存在的资源,如何捕获ThreadAbortException
?”您可以使用普通{ {1}}阻止。 catch
可能像任何其他异常一样被捕获,但它会在catch块的末尾自动再次引发。但是,正如克里斯所提到的,如果进程退出,则根本不会引发ThreadAbortException
。