liu_uestc的个人空间 https://blog.eetop.cn/62687 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

C++中句柄和指针的区别(转)

已有 7788 次阅读| 2011-9-21 10:23

C++中句柄和指针的区别  

2011-01-27 09:02:35|  分类: VC++ |  标签:句柄和指针的区别   |字号 订阅

从广义上,能够从一个数值拎起一大堆数据的东西都可以叫做句柄。句柄的英文是"Handle",本义就是"柄",只是在计算机科学中,被特别地翻译成"句柄",其实还是个"柄"。从一个小东西拎起一大堆东西,这难道不像是个"柄"吗?
然后,指针其实也是一种"句柄",只是由于指针同时拥有更特殊的含义――实实在在地对应内存里地一个地址――所以,通常不把指针说成是"句柄"。但指针也有着能从一个32位的值引用到一大堆数据的作用,这不是句柄又是什么?
Windows系统中有许多内核对象(这里的对象不完全等价于"面向对象程序设计"一词中的"对象",虽然实质上还真差不多),比如打开的文件,创建的线程,程序的窗口,等等。这些重要的对象肯定不是4个字节或者8个字节足以完全描述的,他们拥有大量的属性。为了保存这样一个"对象"的状态,往往需要上百甚至上千字节的内存空间,那么怎么在程序间或程序内部的子过程(函数)之间传递这些数据呢?拖着这成百上千的字节拷贝来拷贝去吗?显然会浪费效率。那么怎么办?当然传递这些对象的首地址是一个办法,但这至少有两个缺点:
暴露了内核对象本身,使得程序(而不是操作系统内核)也可以任意地修改对象地内部状态(首地址都知道了,还有什么不能改的?),这显然是操作系统内核所不允许的;
操作系统有定期整理内存的责任,如果一些内存整理过一次后,对象被搬走了怎么办?
所以,Windows操作系统就采用进一步的间接:在进程的地址空间中设一张表,表里头专门保存一些编号和由这个编号对应一个地址,而由那个地址去引用实际的对象,这个编号跟那个地址在数值上没有任何规律性的联系,纯粹是个映射而已。
在Windows系统中,这个编号就叫做"句柄"。
Handle在Windows中的含义很广泛,以下关于谈到的Handle除非特别说明,将仅限于进程、线程的上下文中。
1、先来谈谈Handle
Handle本身是一个32位的无符号整数,它用来代表一个内核对象。它并不指向实际的内核对象,用户模式下的程序永远不可能获得一个内核对象的实际地址(一般情况下)。那么Handle的意义何在?它实际上是作为一个索引在一个表中查找对应的内核对象的实际地址。那么这个表在哪里呢?每个进程都有这样的一个表,叫句柄表。该表的第一项就是进程自己的句柄,这也是为什么你调用GetCurrentProcess()总是返回0x7FFFFFFF原因。
简单地说,Handle就是一种用来"间接"代表一个内核对象的整数值。你可以在程序中使用handle来代表你想要操作的内核对象。这里的内核对象包括:事件(Event)、线程、进程、Mutex等等。我们最常见的就是文件句柄(file handle)。
另外要注意的是,Handle仅在其所属的进程中才有意义。将一个进程拥有的handle传给另一个进程没有任何意义,如果非要这么做,则需要使用DuplicateHandle(),在多个进程间传递Handle是另外一个话题了,与这里要讨论的无关。
2、进程ID
首先,进程ID是一个32位无符号整数,每个进程都有这样的一个ID,并且该ID在系统范围内是唯一的。系统使用该ID来唯一确定一个进程。
深入些说,系统可能使用进程ID来计算代表该进程的内核对象的基地址(及EPROCESS结构的基地址),具体的计算公式你可以去问微软的OS开发人员。
3、HINSTANCE
HINSTANCE也是一个32无符号整数,它表示程序加载到内存中的基地址。
父进程创建子进程时使用CreateProcess()时将bInheriteHandle设为TRUE。这样,系统将把父进程中可继承的句柄的项目复制到子进程的句柄表中,同时增加对象的引用计数。在父子进程中,标识内核对象所用的句柄值是完全一样的。

  对象句柄的继承性有个特征:当使用它时,子进程不知道它已经继承了任何句柄。子进程为了确定它期望的内核对象的句柄值,最常用的方法是将句柄值作为一个命令参数递给子进程。该子进程的初始化代码对命令行进行分析(如用sscanf()),并取出句柄。可以这样做的原因是父子进程中共享内核对象的句柄值是一样的。
  其它的方法如父进程等待子进程完成初始化(使用WaitForInputIdle()),然后发送一条消息给子进程的某线程。
  第三种方法是父进程将一个环境变量加到环境程序块中。该变量的名字是子进程知道要查找的某种信息,而变量的信息则是内核对象要继承的值。可以用GetEnviromentVariable()获取环境变量。
  总之,父进程要把句柄值传递给子进程。例如楼上的hMutex,子进程得到它的值后,可以直接WaitForSingleObject(hMutex,...),而不用再去CreateMutext或OpenMutex


Link URL: http://blog.sina.com.cn/s/blog_466496f30100x85s.html

点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 0

    粉丝
  • 0

    好友
  • 0

    获赞
  • 1

    评论
  • 309

    访问数
关闭

站长推荐 上一条 /2 下一条


小黑屋| 手机版| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-12-22 16:15 , Processed in 0.013262 second(s), 6 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部