1 CreateThread函数调用后发生事情:
1.1:创建一个系统内核对象,并且初始化系统内核对象
线程的内核对象包括:context(设备上下文),使用计数,暂停计数,退出代码,已通知。
使用计数 = 2;暂停计数 = 1;退出代码 = STILL_ACTIVE;已通知=FALSE;上下文之SP(堆栈指针)= 线程的入口函数地址,上下文之IP= BaseThreadStart,线程内核对象如下图所示:
1.2 在进程的地址空间上分配用于线程堆栈的内存
传入堆栈的第1个参数是CreateThread函数的lpParameter,第2个参数是lpStartAddress。
1.3 检查CREATESUSPENDED是否传递给CreateThread函数,如果没有,那么暂停计数变为0,
2 线程的开始执行
线程的内核对象以及堆栈初始化完成以后,操作系统调用VOID RtlUserThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOIDpvParam)函数来执行新的线程函数。这个函数的原型如下所示:
VOID RtlUserThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam) {
__try {
ExitThread((pfnStartAddr)(pvParam));
}
__except(UnhandledExceptionFilter(GetExceptionInformation())) {
ExitProcess(GetExceptionCode());
}
// NOTE: We never get here.
}
这个函数不是由别的函数来调用的,而是操作系统调用的,函数的两个参数也是由操作系统压入现成的栈内的。函数的调用方式是_cdel,这是C/C++函数调用的默认方式。不过这次的调用者不是操作系统而是函数。执行RtlUserThreadStart函数时候发生的事情:
<1>在线程函数处建立SHE帧,负责运行库相关的事情。
<2>系统调用线程函数,把lpParam传递给线程函数
<3>线程函数返回时,调用ExitThread函数,线程内核计数减1
<4>如果线程产生一个没有处理的异常,那么SEH帧将处理该异常条件。通常,这意味着一个消息框呈现给用户,当用户撤销消息框时,RtlUserThreadStart函数调用ExitProcess来终结整个进程。
3 C/C++ 运行时
在早些时候,VC++ 有6个C/C++运行库,其中有两个是属于单线程的,但是现在已经没有了专门属于单线程的运行库。现在的6个运行时库如下所示: