当一个.NET控制台应用程序在Console.ReadLine()上阻塞时会发生什么?

10

今天我遇到了一个有趣的面试问题,假设你有以下控制台应用程序:

static void Main(string[] args) 
{
    Console.WriteLine("Hello world");
    Console.ReadLine();
}

当程序执行到Console.ReadLine()时,执行被暂停,程序等待从键盘输入。此时有多少个线程,它们处于什么状态,例如正在运行、已暂停等?

我认为面试官想要了解的是 .NET 控制台应用程序所包含的线程以及它们如何相互配合与底层操作系统的 IO 子系统进行交互。


6
就应用程序而言,只有一个线程。如果操作系统在后台创建额外的线程,那对应用程序来说是无关紧要的实现细节。 - Cody Gray
1
Console.ReadLine(); 只会阻塞当前线程的执行。 - a-ctor
面试官可能具有WinDbg调试的经验,https://www.jayway.com/2011/04/26/getting-started-with-managed-dump-files-using-windbg/ 以便比你更深入地了解进程和线程。如果你掌握了这些工具和技巧,这样的问题在未来就不会成为障碍。 - Lex Li
2个回答

13

没有确定的数字。

你的代码只在一个线程上运行 - 主线程。调用Console.ReadLine不会创建新的线程,它只是开始一个I/O请求并等待其被处理 - 这不需要线程,但由于你使用同步API,没有办法释放你的线程,所以它就阻塞了。如果面试官只想要一个数字,这个数字就是 - 它是你唯一拥有的应用程序线程,其他所有线程都是实现细节。

有很多基础设施线程 - 垃圾收集器线程是主要线程,其中一些线程会一直被创建和销毁。

最后,还有介于两者之间的线程 - 特别是线程池。由于你没有使用线程池,它将具有默认数量的线程 - 除非配置指定,否则通常为每个逻辑CPU核心的两个线程。

现实甚至更深入。例如,.NET线程是托管线程,它们可以在运行时自由地跳转到“本机”线程。然而,除非你正在编写自己的.NET运行时或操作系统 :) 或者与依赖于本机线程亲和性的本机代码进行重型Interop(再次不是很常见),否则你永远不需要关心这个。

我怀疑这个问题的主要目的是让你谈论Windows线程模型是如何工作的,.NET如何处理线程以及典型Windows /.NET应用程序中有哪些类型的线程。但主要还是为了让你说话 :P


“跳过本地线程”是指“创建”吗?这是我不熟悉的跳过惯用语,还是一个打字错误? - Cody Gray
我明白了。是的,“between”会澄清事情。跳过,切换,跳过/切换,随便哪个。 - Cody Gray
也许他想了解GC线程之类的内容,但不能确定。我认为他只是在谈论托管线程而不是操作系统线程。无论如何,感谢您的回答。 - alex.tashev
@alex.tashev 是的,但请注意,就 .NET 而言,根本不需要垃圾回收器。一个 .NET 实现可以完全有效地一直分配内存而不进行任何回收,实际上过去曾经使用过这种方法(在进程退出时进行“回收”),尽管我不知道是否存在任何现有的 .NET 运行时这样做。了解您的运行时环境很重要,但不要过于依赖它 - 规范是唯一的合同,其他所有内容都是实现细节。 - Luaan

3

我同意Luuan的观点,因此根据你的面试官的意思,例如在主线程之外可能还有运行VisualStudio的线程。顺便说一下,这个线程可以被禁用(在VS2015中:项目属性 > 调试选项卡 > 取消选中启用Visual Studio托管进程)。

如果您正在使用Visual Studio,在调试过程中应该能够看到这些线程。

正在运行的代码:

static void Main(string[] args)
{
    Console.WriteLine("Hello world");           
    Console.ReadLine();
}

线程窗口(在VS2015中:调试->窗口->线程):

enter image description here

我在您的示例中添加了一个新的线程:

运行的代码:

static void Main(string[] args)
{
    Console.WriteLine("Hello world");
    new Thread(DoSomethingElse).Start();            
    Console.ReadLine();
}

private static void DoSomethingElse()
{
    while (true)
    {
        Thread.SpinWait(100);
    }
}

线程窗口:

enter image description here


情景是你从命令行运行可执行文件 - 我忘了提到这一点,所以我认为他不是指额外的VS线程。 - alex.tashev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接