【问题标题】:Background thread executed event after foreground thread exited?前台线程退出后后台线程执行事件?
【发布时间】:2019-05-29 10:15:18
【问题描述】:

我正在查看 ThreadPool 的 Microsoft 文档,他们解释说 ThreadPool 线程是后台线程,如果所有前台线程都已终止,则不会保持应用程序运行。

这里是sn-p的代码:

public static void Main()
{
    ThreadPool.QueueUserWorkItem(ThreadProc);
    Console.WriteLine("From main foreground thread");
    //Thread.Sleep(1000);

    Console.WriteLine("Exiting from main");
}

static void ThreadProc(object stateInfo) {
    Console.WriteLine("From the thread pool");
}

如果 Thread.Sleep(1000) 未注释,则可以确保后台线程将在主前台线程退出之前完成。但是当我们评论睡眠部分时,我也会得到一个输出:

From main foreground thread
Exiting from main
From the thread pool

这意味着即使主前台线程已经退出,后台线程仍然会执行。为什么会这样?

【问题讨论】:

  • 这是一个经典的线程竞赛错误。在 Console.WriteLine() 调用之后和 CLR 可以终止程序之前发生的事情确实。几乎不需要,线程池线程很可能阻塞在互斥锁上,从而防止控制台的输出混淆。因此,轮到它只需要几纳秒。在非托管代码中运行,CLR 在完成之前无法中止。
  • +1。在您当前的代码中,只需将 Thread.Sleep(1000); 放在 Console.WriteLine("From the thread pool"); 之前,就可以看到它不再显示了。
  • 永远,永远不要使用 Sleep() 修复线程争用错误。
  • 我的评论不是关于修复比赛,而是关于显示程序不等待池中的线程完成。

标签: c# multithreading threadpool


【解决方案1】:

Main 方法的结束并不意味着“前台”线程已经退出。即使有,也不代表你的进程已经终止。

通常,当进程中运行的所有线程(包括线程池中的已排队工作的线程)终止时,进程就会停止。但是,如果您使用 ExitProcess 退出进程。 CLR 的工作方式稍微复杂一些 (see here),它在应用程序真正存在之前进行了相当多的清理工作。

因此,在所有工作线程都被杀死之前,有相当长的时间可以完成工作。

【讨论】:

  • 所以所有线程(包括后台线程)都应该被终止。终止是指在进程实际退出的时间内被杀死或执行。我说的对吗?
  • 线程池线程是后台线程,因此they do not keep the program running。停止所有前台线程后,系统将停止所有后台线程并关闭。
  • 别忘了关闭应用需要时间,后台线程可以使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-15
  • 1970-01-01
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多