CloseHandle疑惑

来源:互联网 发布:如何购买淘宝网店 编辑:程序博客网 时间:2024/06/10 00:40

句柄实际上是指向内核对象内存块的指针、访问掩码、标志.(其实微软为了隐藏里面的结构体,故意以void*来表示)

对于Windows的线(进)程而言,系统总是维护一个与当前进程(线)相关的一张句柄表.当我们创建一个进程(线)时,句柄使用计数就会加1,因为继承关系(继承父进程的句柄)而产生后的句柄,使用计数同样加1.但是CloseHandle的实质是告诉进程(线程),当前句柄使用计数减1,如果句柄使用计数减为0,那么内核对象会被销毁,同样线程也会结束.(前提是线程还没有运行),也就是说,当系统要运行的时候,它就会检查句柄使用计数是否为0,如果是0,则退出进(线)程,否则执行进(线)程.

说了一大堆,还是看代码吧!

代码一:

DWORD WINAPI ThreadProc1( PVOID pvParam ){cout<<"thread one running..."<<endl;for( int i = 0;i< 10000;++ i ){cout<<"i  =  :"<<i<<endl;}return 0;}void main(){DWORD dwThread1ID;HANDLE hThread = CreateThread( NULL,0,ThreadProc1,NULL,0/*CREATE_SUPPEND*/,&dwThread1ID );CloseHandle( hThread );getchar();return;}


使用CloseHandle时,线程已经结束(可以通过Process Explorer来查看)但是输出依然在继续.

这个地方不是很理解.开始以为是10000不够大,cpu实际上已经处理完成,后来加大数字,而且把cout<<"thread one running..."<<endl;移至循环内,经过发现线程还是闪一下就退出了,但是输出并没有结束.这就奇怪了.

代码二:

DWORD WINAPI ThreadProc1( PVOID pvParam ){cout<<"thread one running..."<<endl;for( int i = 0;i< 10000;++ i ){cout<<"i  =  :"<<i<<endl;}return 0;}void main(){DWORD dwThread1ID;HANDLE hThread;hThread = CreateThread( NULL,0,ThreadProc1,NULL,0,&dwThread1ID );Sleep(100);SuspendThread( hThread );CloseHandle( hThread );ResumeThread( hThread );//hThread已经无效,但当线程暂停,当前线程无法操作之前的线程.getchar();return;}


这个程序开始确实想错了,本来是想测试线程暂停和执行时,内核使用计数对其的影响,后来发现证明我的想法是错的.原因见注释.

这里关于CloseHandle,再回过头看msdn,里面就线程问题专门进行了说明:

Closing a thread handle does not terminate the associated thread. To remove a thread object, you must terminate the thread, then close all handles to the thread.

意思大概是要想终止线程,必须关闭所有的句柄并且终止线程.单独关闭句柄并不能使线程结束.

纠结了很久,再次查看核心编程,它上面是这样说的,调用CloseHandle,如果句柄有效,系统将根据内核对象的地址找到使用计数,然后递减,如果计数为0,内核对象将被销毁,并从内存中除去.那它的意思是创建一个线程的时候,使用计数不是1而是2?如果是1的话,那肯定内核对象将被销毁了.也就不会出现上述代码出现的问题.

那么可以有两种解释:一种是内核对象和线程是两个并不相关的东西.二中解释就是之前所说的计数为2.

前一种解释是不通的:首先内核对象是系统为管理线程而创建的.如果内核对象都销毁了,线程就变成了游离态,这岂不是一个天大的bug.我估计微软也不可能做这么愚蠢的事情.

后一种解释的话,好像不是怎么好理解.实际上核心编程针对CreateProcess有了对内核对象的引用计数的说明.书中指出创建进程内核对象和线程()对象的时候,系统会每个对象指定一个初始化引用计数1.然后在CreateProcess返回之前,它使用完全的权限来打开进程进程对象和线程对象.并保存在PROCESS_INFORMATION结构中.这是因为是再一次打开(可以理解成引用),对应的使用技术自然是+1(也就是2).

很悲剧的一件事情,弄了半天居然就这么简单.当初在看的时候也没有太留意.导致出现这么大的错误.后来在网上发现原来已经有人发表过类似的博客了.这更加让人悲剧.

原创粉丝点击