为什么Windows 10会在我的程序中启动额外的线程?

Adr*_*thy 32 c++ windows multithreading threadpool

使用Visual Studio 2015,在一个新的空C++项目中,为Console应用程序构建以下内容:

int main() {
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在返回时设置断点并在调试器中启动程序.在Windows 7上,从断点开始,该程序只有一个线程.但在Windows 10上,它有五个(!)线程:主线程和四个"工作线程"等待同步对象.

谁在启动线程池(或者我如何找到)?

Han*_*ant 25

Crystal ball表示Debug> Windows> Threads窗口显示了这些线程ntdll.dll!TppWorkerThread.请务必让Microsoft Symbol Server自行查看,使用工具>选项>调试>符号.

这也发生在VS2013中,所以它绝对不是由新的VS2015诊断功能造成的,@ Adam的猜测是不正确的.

TppWorkerThread()是线程池线程的入口点.当我在此函数上使用Debug> New Breakpoint> Function Breakpoint设置断点时.我很幸运在第二个线程池线程开始执行时捕获第一个线程池线程的堆栈跟踪:

    ntdll.dll!_NtOpenFile@24()  Unknown
    ntdll.dll!LdrpMapDllNtFileName()    Unknown
    ntdll.dll!LdrpMapDllSearchPath()    Unknown
    ntdll.dll!LdrpProcessWork() Unknown
    ntdll.dll!_LdrpWorkCallback@12()    Unknown
    ntdll.dll!TppWorkpExecuteCallback() Unknown
    ntdll.dll!TppWorkerThread() Unknown
    kernel32.dll!@BaseThreadInitThunk@12()  Unknown
    ntdll.dll!__RtlUserThreadStart()    Unknown
>   ntdll.dll!__RtlUserThreadStart@8()  Unknown
Run Code Online (Sandbox Code Playgroud)

显然,加载器正在使用Windows 10上的线程池来加载DLL.这肯定是新的:)此时主线程也在加载器中执行,并发工作.

因此,Windows 10正在利用多个内核来更快地初始化进程.非常一个功能,而不是一个bug :)

  • @Voo:使用本机代码的一大好处是不支付您不使用的资源.如果我的应用程序不需要线程池,那么它仍然需要支付四个线程的堆栈空间似乎很奇怪.如果我使用具有大型运行时系统的框架,我不会感到惊讶.但即使最简单的程序现在也会旋转多个线程,即使它从未使用它们. (6认同)
  • @Joshua:不,不是。从来没有。 (3认同)
  • 后来写了一篇文章引用此答案,并详细介绍了加载程序线程池:https://threatvector.cylance.com/en_us/home/windows-10-parallel-loading-breakdown.html (3认同)
  • 我的问题是:假设我已经描述了我的服务器,我看到5个线程带来了最大的性能.新版本的Windows是否可以自由使用我已创建的线程中的更多线程?我不是要求在Web服务器上使用线程池,而是你在这里提出的问题,这是"程序中不需要的os线程" (2认同)
  • 请注意,Windows有权创建尽可能多的线程.如果你的程序依赖于你没有自己创建的线程,那就是一个bug. (2认同)
  • 这是一个BUG!所有用户创建的线程和main上的ExitThread()不再导致进程终止; 这是契约行为. (2认同)
  • 同意@AdrianMcCarthy,作为开发人员,我至少应该能够禁用这样的功能。在这样的应用程序中使用 5 个线程似乎并不明智,即使这样的应用程序不太可能。但这是一个坏主意的另一个原因 - 当前正在处理在 Windows 线程池中崩溃的应用程序(该应用程序未使用线程池),并且检查的崩溃转储实际上并未揭示问题所在。我控制的代码没有崩溃,但 Windows 线程池崩溃了(仅在 Win10 上,并且仅在某些情况下)。几乎不可能确定根本原因。 (2认同)