内核对象与句柄的关系
2013-12-09 20:07
225 查看
一:一个对象是不是内核对象,通常可以看创建此对象API的参数中是否需要:PSECURITY_ATTRIBUTES 类型的参数。
二:内核对象只是一个内存块,这块内存位于操作系统内核的地址空间,内存块中存放一个数据结构(此数据结构的成员有如:安全描述符、使用计数等)。
三:每个进程中有一个句柄表(handle table),这个句柄表仅供内核对象使用,如下图:
四:解开此中的秘密
比如调用创建一个线程的API:
HANDLE hThread ;
DWORD threadId;
hThread = CreateThread(... , &threadId);
此时发生的事情是:系统查找句柄表,找到一项可用的分配给以上创建的线程;,hThread >> 2 得到句柄在句柄表中的索引(Windows操作系统内部使用hThread最后两位,所以
右移两位得到真正的索引);也是此时内核对象被创建,其数据结构中的引用计数初始为1(这样理解:只要内核对象被创建,其引用计数被初始化为1),这里实则发生两件事:创建了一个内核对象和创建线程的函数打开了此对象,所以内核对象的引用计数加1,这时引用计数就为2了。
当调用CloseHandle(hThread); 时发生这样的事情:系统通过hThread计算出此句柄在句柄表中的索引,然后把那一项处理后标注为空闲可用的项,内核对象的引用计数减1即此时此内核对象的引用计数为1,之后这个线程句柄与创建时产生的内核对象已经没有任何关系了。
问题:我们知道只有当内核对象的引用计数为0时,内核对象才会被销毁,而此时它的引用计数为1,那它什么时候会被销毁?
答:当此线程结束的时候,它的引用计数再减1即为0,内核对象被销毁。此时又有一个新问题产生:我们已经关闭了线程句柄,也就是这个线程句柄已经和内核对象没有瓜葛了,那么那个内核对象是怎么又可以和此线程联系起来了呢? 我觉得是创建线程时产生的那个线程ID,接下来我就证明那个ID与内核对象是有联系的:
请看如下简单的程序:
#include <stdio.h>
#include <windows.h>
#include <WinBase.h>
DWORD WINAPI ThreadProc( LPVOID lpParameter)
{
printf("I am comming...");
while (1){}
return 0;
}
int main()
{
HANDLE hThread;
HANDLE headle2;
DWORD threadId;
hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, &threadId);
CloseHandle(hThread); // 关闭了线程句柄
headle2 = OpenThread(THREAD_QUERY_INFORMATION, FALSE, threadId);
headle2= OpenThread(THREAD_QUERY_INFORMATION, FALSE, threadId);
headle2 = OpenThread(THREAD_QUERY_INFORMATION, FALSE, threadId);
return 0;
}
图1:
图2:
调试此程序观察headle2的值,可以发现headle2的值是有效的,即函数调用是成功的,证明了线程ID与线程创建当初产生的内核对象是有关系的。
可以猜想:当线程结束时,系统通过线程ID与内核对象联系,使其引用计数减1,为0内核对象被销毁。
ps:观察以上两图,当把CloseHandle(hThread)这一句注释掉,以上程序三次调用OpenThread(),返回值是不相同的,说明返回的句柄不是原来句柄表中原来
的索引项,而是新建了一个内容一样的索引项。让CloseHandle(hThread); 这句也执行,再看看结果:hThread与headle2 的值是一样,证明了系统
管理句柄表的规则:我们把hThread关闭之后,它所在的索引项就被标记为可用;当需要向句柄表中加入新项时会查找第一项可用的索引项,这就是
hThread与headle2 的值是一样的原因。
二:内核对象只是一个内存块,这块内存位于操作系统内核的地址空间,内存块中存放一个数据结构(此数据结构的成员有如:安全描述符、使用计数等)。
三:每个进程中有一个句柄表(handle table),这个句柄表仅供内核对象使用,如下图:
四:解开此中的秘密
比如调用创建一个线程的API:
HANDLE hThread ;
DWORD threadId;
hThread = CreateThread(... , &threadId);
此时发生的事情是:系统查找句柄表,找到一项可用的分配给以上创建的线程;,hThread >> 2 得到句柄在句柄表中的索引(Windows操作系统内部使用hThread最后两位,所以
右移两位得到真正的索引);也是此时内核对象被创建,其数据结构中的引用计数初始为1(这样理解:只要内核对象被创建,其引用计数被初始化为1),这里实则发生两件事:创建了一个内核对象和创建线程的函数打开了此对象,所以内核对象的引用计数加1,这时引用计数就为2了。
当调用CloseHandle(hThread); 时发生这样的事情:系统通过hThread计算出此句柄在句柄表中的索引,然后把那一项处理后标注为空闲可用的项,内核对象的引用计数减1即此时此内核对象的引用计数为1,之后这个线程句柄与创建时产生的内核对象已经没有任何关系了。
问题:我们知道只有当内核对象的引用计数为0时,内核对象才会被销毁,而此时它的引用计数为1,那它什么时候会被销毁?
答:当此线程结束的时候,它的引用计数再减1即为0,内核对象被销毁。此时又有一个新问题产生:我们已经关闭了线程句柄,也就是这个线程句柄已经和内核对象没有瓜葛了,那么那个内核对象是怎么又可以和此线程联系起来了呢? 我觉得是创建线程时产生的那个线程ID,接下来我就证明那个ID与内核对象是有联系的:
请看如下简单的程序:
#include <stdio.h>
#include <windows.h>
#include <WinBase.h>
DWORD WINAPI ThreadProc( LPVOID lpParameter)
{
printf("I am comming...");
while (1){}
return 0;
}
int main()
{
HANDLE hThread;
HANDLE headle2;
DWORD threadId;
hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, &threadId);
CloseHandle(hThread); // 关闭了线程句柄
headle2 = OpenThread(THREAD_QUERY_INFORMATION, FALSE, threadId);
headle2= OpenThread(THREAD_QUERY_INFORMATION, FALSE, threadId);
headle2 = OpenThread(THREAD_QUERY_INFORMATION, FALSE, threadId);
return 0;
}
图1:
图2:
调试此程序观察headle2的值,可以发现headle2的值是有效的,即函数调用是成功的,证明了线程ID与线程创建当初产生的内核对象是有关系的。
可以猜想:当线程结束时,系统通过线程ID与内核对象联系,使其引用计数减1,为0内核对象被销毁。
ps:观察以上两图,当把CloseHandle(hThread)这一句注释掉,以上程序三次调用OpenThread(),返回值是不相同的,说明返回的句柄不是原来句柄表中原来
的索引项,而是新建了一个内容一样的索引项。让CloseHandle(hThread); 这句也执行,再看看结果:hThread与headle2 的值是一样,证明了系统
管理句柄表的规则:我们把hThread关闭之后,它所在的索引项就被标记为可用;当需要向句柄表中加入新项时会查找第一项可用的索引项,这就是
hThread与headle2 的值是一样的原因。
相关文章推荐
- 内核对象句柄的继承
- Windows进程内核对象句柄表
- -跨越进程边界共享内核对象【对象句柄的继承性】
- Delphi版多开源码,也就是遍历系统内核对象句柄
- Windows内核对象(1) -- 内核对象与句柄
- 《windows核心编程系列》三谈谈内核对象及句柄的本质
- 深入解析MFC -- 句柄与对象的关系
- windows笔记-进程的内核对象句柄表
- MFC 对象与Win32 SDK 句柄的映射关系
- windows笔记-跨越进程边界共享内核对象【复制对象句柄】
- windows笔记-跨越进程边界共享内核对象【对象句柄的继承性】
- 深入解析MFC -- 句柄与对象的关系
- 线程伪句柄转实句柄 内核对象共享
- 内核对象及句柄的本质区别
- 跨越进程边界共享内核对象【复制对象句柄】
- 《windows核心编程系列》三谈谈内核对象及句柄的本质
- windows内核对象句柄
- 句柄与MFC对象关系和相互获取
- 内核对象与句柄
- windows编程(1)-句柄,内核对象