预期的ThreadAbort用于后台线程

时间:2012-02-05 20:04:29

标签: c# .net multithreading

我有以下内容。

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以清除线程中可能存在的资源?

3 个答案:

答案 0 :(得分:4)

首先,应用程序可能没有退出,因为你没有将它们变成后台线程。我的猜测是任务管理器会显示你的EXE意外运行的副本。在调用Start之前,需要在线程对象上将Thread.IsBackground设置为true。

其次,您期望的行为会被the documentation明确揭穿:

  

注意

     

当公共语言运行库(CLR)停止后台线程时,   在托管可执行文件中的所有前台线程结束后,它   使用System.Threading.Thread.Abort。因此,你不能使用   ThreadAbortException用于检测何时存在后台线程   由CLR终止。

编辑:

当一个进程退出时,不需要清理工作线程持有的资源,因为,你知道,进程正在退出。关于后台线程的合同是它们可以在进程退出时随时被杀死。因此,如果您的后台线程正在执行需要事务正确性的操作,则它们可能不应该是后台线程。制作'em前台线程,让他们定期检查或等待重置事件,看看是否应该退出并允许进程结束。

答案 1 :(得分:4)

当CLR关闭进程时,它不会调用Thread.Abort或类似的东西。您的线程方法不会像main方法一样退出。

  1. 当您离开main方法或调用Environment.Exit时,它首先要做的是用超时(在.NET 2.0中为2秒)完成所有对象,然后它将继续终止应用程序而不管当前挂起的终结器
  2. 接下来将调用Critical Finalizers。
  3. 然后所有线程都被挂起,因此在CLR关闭时它们不会造成伤害。
  4. 您的申请已退出。

答案 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