C# 当.NET控制台应用程序在console.ReadLine()上阻塞时会发生什么情况?

C# 当.NET控制台应用程序在console.ReadLine()上阻塞时会发生什么情况?,c#,.net,multithreading,C#,.net,Multithreading,今天我有一个有趣的面试问题。假设您有以下控制台应用程序: static void Main(string[] args) { Console.WriteLine("Hello world"); Console.ReadLine(); } 当到达Console.ReadLine()行时,执行暂停,程序等待键盘输入。此时有多少线程,它们处于什么状态,例如运行、挂起等 我想面试官想要了解的是组成.NET控制台应用程序的线程,以及它们如何协同工作以与底层操作系统的IO子系统交互。没有

今天我有一个有趣的面试问题。假设您有以下控制台应用程序:

static void Main(string[] args) 
{
    Console.WriteLine("Hello world");
    Console.ReadLine();
}
当到达Console.ReadLine()行时,执行暂停,程序等待键盘输入。此时有多少线程,它们处于什么状态,例如运行、挂起等


我想面试官想要了解的是组成.NET控制台应用程序的线程,以及它们如何协同工作以与底层操作系统的IO子系统交互。

没有确切的数字

您的代码只在一个线程(主线程)上运行。调用
Console.ReadLine
不会创建新线程,它只是启动I/O请求并等待处理——这不需要线程,但由于您使用的是同步API,因此无法释放线程,因此它只是阻塞。如果面试官只想要一个数字,这就是这个数字——这是你唯一的应用程序线程,其他一切都是一个实现细节

有很多基础结构线程——垃圾收集器线程是主要的线程,其中一些线程一直在创建和销毁

最后,在这两者之间的某个地方有线程——最显著的是线程池。由于您不使用线程池,因此它将具有默认的线程数-除非配置另有说明,否则每个逻辑CPU核心通常有两个线程

现实更为深刻。例如,.NET线程是托管线程,它们可以根据运行时的意愿在“本机”线程之间跳过。但是,除非您正在编写自己的.NET运行时或操作系统:),或者使用依赖于本机线程关联性的本机代码进行大量互操作(同样,也不是很常见),否则您永远不需要真正关心这一点


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

我同意Luuan的观点,因此,根据你的面试官的意思,在主线程之外还有一些VisualStudio线程。顺便说一句,可以禁用此线程(在VS2015中:项目属性>调试选项卡>取消选中启用Visual Studio宿主进程)

如果您使用的是Visual Studio,则应该能够在调试期间看到线程

运行代码:

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

private static void DoSomethingElse()
{
    while (true)
    {
        Thread.SpinWait(100);
    }
}
线程窗口(在VS2015中:调试->窗口->线程):

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

运行代码:

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

private static void DoSomethingElse()
{
    while (true)
    {
        Thread.SpinWait(100);
    }
}
线程窗口:


就应用程序而言,只有一个线程。如果操作系统在后台创建额外的线程,从应用程序的角度来看,这是一个无关的实现细节仅阻止正在执行它的线程。面试官可能具有WinDbg调试经验,因此他/她可以比你更深入地了解进程和线程。如果你掌握了工具和技巧,这些问题在将来不会成为障碍。你说的“跳过本机线程”是指创建吗?这是我不熟悉的skip的惯用用法,还是仅仅是一个拼写错误?我明白了。是的,“中间人”会把事情弄清楚的。Skip,switch,Skip/switch,随便哪个。也许他想听听GC线程之类的东西——不能确定。我想他只是在谈论托管线程,而不是操作系统线程。谢谢你的回答。@alex.tashev是的,但是请注意,就.NET而言,根本不需要垃圾收集器。对于.NET实现来说,反复分配而不收集是完全有效的,事实上,这种方法在过去已经被使用过(当进程退出时进行“收集”),尽管我不知道有任何现有的.NET运行时会这样做。了解您的运行时现实是很好的,但不要过于依赖它-规范是唯一的契约,其他一切都是实现细节。场景是您从命令行运行可执行文件-我忘了提到这一点,所以我不认为他指的是额外的VS线程。