现在的位置: 首页 > 综合 > 正文

Windows中一些与Thread有关的内部细节

2013年10月20日 ⁄ 综合 ⁄ 共 1836字 ⁄ 字号 评论关闭

1.当线程被创建之后,该线程的内核对象的引用计数是2,当线程以任何方式退出时,该引用计数减去1,当CreateThread所返回的句柄被关闭后,引用计数再减去1。因此是初始值是2才能保证在正常情况下线程结束并且对象句柄被关闭后引用计数是0。

2.线程还有另一个计数值,叫做挂起计数,初始值为1。如果线程在创建时没有指定CREATE_SUSPENDED标志,那么系统就自动将这个计数值减去1。这时线程就能够开始执行。每一次调用SuspendThread都会将该线程的挂起计数增加1,每一次调用ResumeThread都会将挂起计数减少1。当且仅当挂起计数不超过0的时候,线程才会执行

3.线程的内部结构中有两个重要的指针,一个是栈指针(SP),一个是指令指针(IP),IP指向一个从NTDLL中导出的名为RtlUserThreadStart的函数地址。从而在CPU看来,线程执行实际上是执行了以下的代码。

VOID RtlUserThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam) {
   __try {
      ExitThread((pfnStartAddr)(pvParam));
   }

   __except(UnhandledExceptionFilter(GetExceptionInformation())) {
      ExitProcess(GetExceptionCode());
   }
   // NOTE: We never get here.

}

可见,线程函数在返回之后,RtlUserThreadStart调用了ExitThread将线程函数的返回值传递给了操作系统。

这样的内部结构保证了函数的顺利结束,从而保证了在函数内部产生的所有临时变量都会正常的销毁。同时,这样说明了为什么在线程内部调用exitthread会导致临时变量无法销毁。

------------------------------------

实战:

挂起一个线程,使其挂起计数超过1,然后再Resume,看看线程是否真的不能被执行。

#include "stdafx.h"
#include <Windows.h>
HANDLE g_hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
DWORD WINAPI ThreadToSuspend(LPVOID pParam)
{
	printf_s("I run!\n");
	return 0 ;
}
DWORD WINAPI ThreadToSuspendOther(LPVOID pParam)
{
	HANDLE hThread = (HANDLE) pParam;
	printf_s("Pre suspend count:%u\n",SuspendThread(hThread));
	SetEvent(g_hEvent);
	return 0 ;
}
int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hThreadSuspended = CreateThread(NULL,NULL,ThreadToSuspend,NULL,CREATE_SUSPENDED,NULL);
	SuspendThread(hThreadSuspended);
	HANDLE hThreadSuspender = CreateThread(NULL,NULL,ThreadToSuspendOther,hThreadSuspended,NULL,NULL);
	WaitForSingleObject(g_hEvent,INFINITE);
	::ResumeThread(hThreadSuspended);
	WaitForSingleObject(hThreadSuspended,INFINITE);
	CloseHandle(hThreadSuspended);
	CloseHandle(hThreadSuspender);
	CloseHandle(g_hEvent);
	return 0;
}

上述代码生成了一个线程用于被挂起,如果线程执行了,那么就会打印一行"I run"

程序用CREATE_SUSPENDED创建线程后又再次调用了挂起函数,此外,还有另外一个线程也会挂起不允许执行的线程,通过SuspendThread的返回值,可以得知上一次的挂起计数。因此最后程序的运行结果是挂起计数为2没有打印出I
run
的结果,即使在main中调用了ResumeThread。从因说明了挂起计数的正确性。

抱歉!评论已关闭.