前台线程不会阻止控制台进程终止?

时间:2016-12-15 02:40:46

标签: c# .net wpf multithreading

在以下WPF代码中,单击一次按钮后,将启动新的前台线程。然后我关闭了WPF窗口,我可以看到在Windows任务管理器中,该进程在Thread.Sleep(100000)结束前不会被终止。我可以理解它,因为前台线程可以阻止进程终止,因为MSDN doc说。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        new Thread(Go).Start();
    }

    private void Go(object obj)
    {
        Thread.Sleep(100000);
    }
}

但是当我在控制台程序中尝试几乎相同的事情时,该过程会在关闭控制台窗口后立即终止。有人可以帮忙解释这些差异吗?

class Program
{
    static void Main(string[] args)
    {
        new Thread(Go).Start();
    }

    private static void Go()
    {
        Thread.Sleep(100000);
    }
}

1 个答案:

答案 0 :(得分:4)

  

但是当我在控制台程序中尝试几乎相同的事情时,该过程会在关闭控制台窗口后立即终止。有人可以帮忙解释这些差异吗?

<强> TL; DR; 区别在于它是一个控制台应用,您点击关闭框。这与从任务管理器中进行核对非常相似。此外,所有控制台应用程序主线程也是前台线程。请参阅本答案末尾的示例。

如果单击控制台应用程序上的关闭框,Windows将终止所有线程并关闭控制台应用程序,无论线程是后台还是前台。对于GUI应用程序,如WinForms或WPF; 的规则“一旦属于某个进程的所有前台线程都已终止,公共语言运行库将结束该进程”。与控制台应用程序不同,单击GUI应用程序上的关闭框和进程终止之间没有直接链接

如果在调试器中运行以下代码,它将等待另一个线程完成。但是,单击关闭框会使进程和控件返回到 Visual Studio ,从而证明该进程确实已退出并且未播放隐藏 - 像Windows Forms一样可以处理前台线程。 (关闭一个WinForms主应用程序窗口,前台线程仍在运行,只关闭窗口,不一定是进程)

namespace ConsoleApplication10
{
    class Program
    {
        static void Main(string[] args)
        {
            new Thread(Go).Start();
            Console.WriteLine("Main thread {0} exiting", Environment.CurrentManagedThreadId);
        }

        private static void Go()
        {
            var thread = Thread.CurrentThread;
            Console.WriteLine("{0} thread {1} sleeping",thread.IsBackground ? "Background" : "Foreground",  thread.ManagedThreadId);
            Thread.Sleep(100000);

        }
    }
}

enter image description here

假设您没有点击关闭框,那么控制台应用程序将不会终止,直到所有线程都完成。

MSDN:

  

一旦属于某个进程的所有前台线程都已终止,公共语言运行库就会结束该进程

证明事情的简单方法

您可以通过以下方式证明此控制台应用行为:

static void Main(string[] args)
{
    var thread = Thread.CurrentThread;
    Console.WriteLine("{0} thread {1} sleeping", thread.IsBackground ? "Background" : "Foreground", thread.ManagedThreadId);
    Thread.Sleep(100000);
}

现在我们不会在这里产生任何新线程,但只需单击关闭框即可将该过程发送到遗忘状态。但是等等,您是否看到主线程实际上是前台线程

enter image description here