概念
从广义上,能够从一个数值拎起一大堆数据的东西都可以叫做句柄(Handle)。
某一程度上,指针也是一种句柄,因为它本身只是个字节大小的地址,却能通过解引用访问到一块大的内存空间,也即一个数值拎起一大堆数据。
在Windows中,每个进程的地址空间中都有一张表,表中保存着一个编号和由这个编号对应的地址,这个编号就是句柄。当我们使用这个句柄时,实际上,我们想要使用的是由句柄在表中对应的地址所指向的内容。
本质
不同的操作系统或编程语言对handle的定义不同,本质都是代表着一个内核对象。
1. 无符号的32位整型
操作系统为每个进程都维护了一个独立的句柄表,用于管理和跟踪进程所拥有的的句柄。当Handle是无符号的32位整型时,可以理解为它代表着一个索引号,在句柄表中,由索引号找到其内核对象对应的实际地址。
它并不指向实际的内核对象,用户模式下的程序永远不可能获得一个内核对象的实际地址(一般情况下)。
内核对象包括:事件(Event)、线程、进程、Mutex等等。我们最常见的就是文件句柄(file handle)。
2. void*类型
void*类型的指针其实本质就是一个过渡型的指针状态,必须要赋予类型(强制类型转换)才能正常使用。
这也意味着此时的句柄比1更具有灵活性,它可以用来表示不同类型的资源或对象,而不仅仅是整数,使得句柄可以更好地适应不同场景和编程需求。
作用
用来标识和引用特定的资源或对象。
- 资源标识:句柄用于唯一标识和引用操作系统提供的各种资源,例如文件、窗口、进程、线程、内存块等。通过句柄,应用程序可以指定和操作它们所需的资源。
- 资源访问:句柄提供了一种访问和操作资源的机制。通过句柄,应用程序可以执行打开、读取、写入、关闭、删除等操作,以及其他与资源相关的操作。
- 内存管理:在动态内存分配中,句柄可以用于引用和操作分配的内存块。通过句柄,可以跟踪和管理分配的内存,包括释放、重分配、共享等操作。
- 事件和通信:句柄可以用于表示和操作事件、信号和通信对象。它们可以用于同步多个线程或进程间的操作,实现进程间通信(IPC)或线程同步。
- 抽象化:句柄提供了一种抽象化的方式,隐藏了底层资源的具体实现细节。应用程序可以通过句柄操作资源,而无需关心底层实现细节,这提供了一定的灵活性和便利性。
总之,句柄在操作系统中扮演着资源管理与访问的重要角色,它们允许应用程序标识、引用和操作各种资源,提供了一种抽象化的机制,简化了资源管理和操作的复杂性。
注意
- Handle仅在其所属的进程中才有意义。将一个进程拥有的handle传给另一个进程没有任何意义,如果非要这么做,则需要使用DuplicateHandle()。
- 地址空间隔离:每个进程都有自己的独立地址空间,句柄在一个进程的地址空间中有意义,但在其他进程的地址空间中没有意义。句柄指向的资源在另一个进程中可能不存在或有不同的表示方式。
- 权限和安全性:句柄通常与进程的权限和安全上下文相关联。通过将句柄传递给其他进程,相当于将资源的访问权限传递给了其他进程,违背了进程间的隔离和安全原则。
- 跨进程通信:如果需要在不同的进程间共享资源或进行通信,通常会使用其他机制,如进程间通信(Inter-Process Communication,IPC)或共享内存等。
- 一般情况下,一个句柄只能操作一个线程。但在某些特定的操作系统中,句柄可能具有操作多个线程的能力。
综上所述,句柄仅在其所属的进程中有意义,传递给其他进程没有实际效果,并且可能导致安全和权限问题。对于跨进程资源访问或共享,需要使用专门的机制来进行管理和通信。