《Windows核心编程系列》 -- 线程基础
作者:网络转载 发布时间:[ 2012/12/4 10:31:42 ] 推荐标签:
九、线程内幕
CreateThread 函数的一个调用 导致 系统创建一个线程内核对象,该对象初的使用计数为2。( 创建线程内核对象加1,返回线程内核对象句柄加1 ),所以除非线程终止,而且 CreateThread 返回的句柄关闭,否则线程内核对象不会被销毁。该线程对象的其它属性也被初始化:暂停计数被设为1,退出代码被设备STILE_ACTIVE(0x103),而且对象被设为未触发状态。
创建了内核对象,系统分配内存,供线程的堆栈使用。此内存是从进程的地址空间分配的,因为线程没有自己的地址空间。系统将来个值写入新线程堆栈的上端,如图1所示,即调用的线程函数及其参数。
每个线程都有自己的一组CPU寄存器,称为线程的上下文(context)。上下文反映了当线程上一次执行时,线程CPU寄存器的状态。CONTEXT结构保存在线程的内核对象中。
当线程内核对象被初始化的时候,CONTEXT结构的堆栈指针寄存器被设为pfnStartAddr在线程堆栈中的地址。而指令指针寄存器被设为RtlUserThreadStart函数的地址。
VOID RtlUserThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam) {
__try {
ExitThread((pfnStartAddr)(pvParam));
}
__except(UnhandledExceptionFilter(GetExceptionInformation())) {
ExitProcess(GetExceptionCode());
}
// NOTE: We never get here.
}
线程完全初始化之后,系统检查CREATE_SUSPENDED标志是否已被传给CreateThread函数。如果此标记没有传递,系统将线程的挂起计数递减至0;随后,线程可以调度给一个处理器去执行。然后,系统在实际的 CPU寄存器中加载上一次在线程上下文中保存的值。现在,线程可以在其进程的地址空间中执行代码并处理数据了。
新线程执行RtlUserThreadStart函数的时候,将发生以下事情:
围绕线程函数,会设置一个结构化异常处理(SEH)帧。这样一来,线程执行期间所产生的任何异常都能得到系统的默认处理。
系统调用线程函数,把传给CreateThread函数的pvParam参数传给它。
线程函数返回时,RtlUserThreadStart调用ExitThread,将你的线程函数的返回值传给它。线程内核对象的使用计数递减,而后线程停止执行。
如果线程产生了一个未被处理的异常,RtlUserThreadStart函数所设置的SEH帧会处理这个异常。通常,这意味着系统会向用户显示一个消息框,而且当用户关闭此消息框时,RtlUserThreadStart会调用ExitProcess来终止真个进程,而不是终止有问题的线程。
当一个进程的主线程初始化时,其指令指针指向RtlUserThreadStart,当RtlUserThreadStart开始执行时,它会调用C/C++运行库的启动代码,后者初始化继而调用你的_tmain或_tWinMain函数。
十、C/C++运行库注意事项
为了保证C和C++多线程应用程序正常运行,必须创建一个数据结构,并使之与使用了C/C++运行库函数的每个线程关联。然后,在调用C/C++运行库函数时,那些函数必须知道去查找主调线程的数据块,从而避免影响到其它线程
编写C/C++应用程序,一定不要调用操作系统的CreateThread函数,相反,应该调用C/C++运行库函数_beginthreadex:
uintptr_t __cdecl _beginthreadex ( void *psa, unsigned cbStackSize, unsigned (__stdcall * pfnStartAddr) (void *),
void * pvParam, unsigned dwCreateFlags, unsigned *pdwThreadID)
{
_ptiddata ptd; // Pointer to thread's data block
uintptr_t thdl; // Thread's handle
// Allocate data block for the new thread.
if ((ptd = (_ptiddata)_calloc_crt(1, sizeof(struct _tiddata))) == NULL)
goto error_return; // Initialize the data block.
initptd(ptd); // Save the desired thread function and the parameter
// we want it to get in the data block.
ptd->_initaddr = (void *) pfnStartAddr;
ptd->_initarg = pvParam;
ptd->_thandle = (uintptr_t)(-1); // Create the new thread.
thdl = (uintptr_t) CreateThread ((LPSECURITY_ATTRIBUTES)psa, cbStackSize, _threadstartex , (PVOID) ptd, dwCreateFlags, pdwThreadID);
if (thdl == 0) {
// Thread couldn't be created, cleanup and return failure.
goto error_return;
} // Thread created OK, return the handle as unsigned long.
return(thdl);
error_return:
// Error: data block or thread couldn't be created.
// GetLastError() is mapped into errno corresponding values
// if something wrong happened in CreateThread.
_free_crt(ptd);
return((uintptr_t)0L);
}
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11