繁体   English   中英

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

[英]Foreground thread don't stop a console process from terminating?

在以下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);
    }
}

但是,当我在控制台程序中尝试几乎相同的操作时,关闭控制台窗口后,该过程立即终止。 任何人都可以帮助解释差异吗?


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);

        }
    }
}

在此处输入图片说明

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

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);
}

现在我们没有在此处生成任何新线程,但是只需单击关闭框就足以将进程发送给遗忘对象。 但是,等等,您是否看到主线程实际上是前台线程

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM