C++ 为什么Win32控制台应用程序启动时会出现三个意外的工作线程?
这是情况的截图 <>我用VS2010创建了Visual C++ Win32控制台应用程序。当我启动应用程序时,我发现有四个线程:一个“主线程”和三个工作线程(我没有编写任何代码) 我不知道这三个工作线程来自哪里。C++ 为什么Win32控制台应用程序启动时会出现三个意外的工作线程?,c++,multithreading,winapi,C++,Multithreading,Winapi,这是情况的截图 我用VS2010创建了Visual C++ Win32控制台应用程序。当我启动应用程序时,我发现有四个线程:一个“主线程”和三个工作线程(我没有编写任何代码) 我不知道这三个工作线程来自哪里。 我想知道这三个线程的作用 提前谢谢 Windows 10实现了一种加载DLL的新方法—多个工作线程并行加载(LdrpWorkCallback)。所有Windows 10进程现在都有几个这样的线程 在Win10之前,系统(ntdll.dll)总是在单个线程中加载dll,但从Win10开始,
我想知道这三个线程的作用
提前谢谢 Windows 10实现了一种加载DLL的新方法—多个工作线程并行加载(
LdrpWorkCallback
)。所有Windows 10进程现在都有几个这样的线程
在Win10之前,系统(ntdll.dll
)总是在单个线程中加载dll,但从Win10开始,此行为发生了变化。现在,ntdll
中存在一个“并行加载程序”。现在可以在工作线程中执行加载任务(NTSTATUS LdrpSnapModule(LDRP\u LOAD\u CONTEXT*LoadContext)
)。几乎每个DLL都有导入(依赖DLL),因此当加载DLL时,它的依赖DLL也会加载,并且这个过程是递归的(依赖DLL有自己的依赖项)
函数void LdrpMapAndSnapDependency(LDRP\u LOAD\u CONTEXT*LoadContext)
通过调用LdrpLoadDependentModule()
(内部调用LdrpMapAndSnapDependency())遍历当前加载的DLL导入表并加载其直接(第一级)依赖的DLL
用于新加载的DLL-因此此过程是递归的)。最后,ldrpmapandsnappendency()
需要调用NTSTATUS LdrpSnapModule(LDRP\u LOAD\u CONTEXT*LoadContext)
将导入绑定到已加载的DLLLdrpSnapModule()
在顶级DLL加载过程中对许多DLL执行,并且该过程对每个DLL都是独立的,因此这是一个并行化的好地方LdrpSnapModule()
在大多数情况下,不会加载新的DLL,而只会将导入绑定到已加载DLL的导出。但是,如果导入解析为转发导出(这种情况很少发生),则会加载新的转发DLL
目前的一些实施细节:
struct\u RTL\u USER\u PROCESS\u参数
new字段-ULONG LoaderThreads
。此LoaderThreads
(如果设置为非零)在新进程中启用或禁用“并行加载程序”。当我们创建一个新流程时,第9个参数是
PRTL\u用户\u流程\u参数ProcessParameters
。但是如果我们使用CreateProcess[Internal]W()
,我们不能直接传递PRTL\u USER\u PROCESS\u参数
,只能传递STARTUPINFO
RTL\u USER\u PROCESS\u PARAMETERS
是从STARTUPINFO
部分初始化的,但是我们不控制ULONG LoaderThreads
,它将始终为零(如果我们不调用ZwCreateUserProcess()
或设置此例程的挂钩)
LdrpInitializeExecutionOptions()
(从LdrpInitializeProcess()
)。此例程检查HKEY\U LOCAL\U MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\
中的几个值(如果
子项存在-通常不存在),包括MaxLoaderThreads
(REG\u DWORD
)-如果存在MaxLoaderThreads
,则其值将覆盖RTL\u用户\u进程\u参数。LoaderThreads
HANDLE LdrpWorkCompleteEvent、LdrpLoadCompleteEvent代码>,用于同步
NTSTATUS LdrpCreateLoaderEvents()
{
NTSTATUS status=ZwCreateEvent(&LdrpWorkCompleteEvent,EVENT\u ALL\u ACCESS,0,SynchronizationEvent,TRUE);
如果(0低!=pps->低| ppv->高!=pps->高)
{
if(LdrpDebugFlags&5)
{
DbgPrint(!!!检测到迂回,禁用并行加载\n”);
LdrpDetourExist=TRUE;
返回;
}
}
}而(pps++,ppv++,--n);
布尔动态政治;
如果(0个加载线程)
:
NTSTATUS LdrpEnableParallelLoading(ULONG LoaderThreads)
{
ldrpdetectedtour();
if(LoaderThreads)
{
LoaderThreads=min(LoaderThreads,16);//不允许超过16个线程
if(LoaderThreads Size=sizeof(TP\u CALLBACK\u ENVIRON);
CallbackEnviron->Pool=LdrpThreadPool;
CallbackEnviron->Version=3;
状态=TpAllocWork(&LdrpMapAndSnapWork,LdrpWorkCallback,0,&CallbackEnviron);//CreateThreadpoolWork
}
返回状态;
}
创建一个特殊的加载程序线程池-LdrpThreadPool
,其中LoaderThreads-1
最大线程数。空闲超时设置为30秒(之后线程退出),并分配PTP_WORK ldrpmap和snapwork
,然后在void LdrpQueueWork(LDRP_LOAD_CONTEXT*LoadContext)
中使用
处理LdrpWorkCompleteEvent,LdrpLoadCompleteEvent;
临界段LdrpWorkQueueLock;
列表\u条目LdrpWorkQueue={&LdrpWorkQueue,&LdrpWorkQueue};
乌龙LdrpWorkInProgress;
布尔LdrpDetourExist;
PTP_池LDRPThread池;
PTP_工作LDRPMAP和Snapwork;
枚举排出任务{
WaitLoadComplete,WaitWorkComplete
};
结构LDRP\u加载\u上下文
{
UNICODE_基于字符串的名称;
pvoidsomestruct;
ULONG Flags;//一些未知的标志
NTSTATUS*pstatus;//加载的最终状态
_LDR_数据_表_ENTRY*ParentEntry;//的'parent'加载dll
_LDR\u DATA\u TABLE\u ENTRY*ENTRY;//this==ENTRY->LoadContext
列表\u条目WorkQueueListEntry;
_LDR_数据_表_条目*替换项;
_LDR_数据_表_项**pvImports;//与图像_导入_描述符piid中的ordef相同
ULONG ImportDllCount;//pvImports的计数