一个关于进程id有深度的高级问题,你能回答么?

wemvyen 2012-07-30 03:08:38
http://bbs.pediy.com/showthread.php?t=154031
问题地址,只有一个人回答了,但感觉好象不对,所以发到csdn来了

请大家帮忙回答回答,讨论讨论

1> 书作者是否矛盾了,该怎样理解
2> 如果进程不退出,但CloseHandle(pi.ProcessHandle)了,id是否可被重用


下面是问题内容
=======================================================================
Windows核心编程5版4章4.2.7节关于子进程id有矛盾问题
99页 "说明"里的文字

说明
应用程序运行期间,必须关闭到子进程及其主线程的句柄,以避免资源泄漏。当然,系统会在你的进程终止后自动清理这种泄漏。但是,如果是一个编写精妙的软件,肯定会在进程不再需要访问一个子进程及其主线程的时候,显式地调用CloseHandle来关闭这些句柄。忘记关闭这些句柄是开发人员最容易犯的错误之一。
应该是建议大家创建子进程后,就用CloseHandle关闭子进程和主线程句柄


但100页 4.3节的向上的一段文字说

要保证一个进程或线程ID不被重用,惟一的办法就是保证进程或线程对象不被销毁。为此,在创建了一个新进程或线程之后,不关闭到这些对象的句柄即可。等到应用程序不再使用ID的时候,再调用CloseHandle来释放内核对象。但是,一旦调用了CloseHandle,再使用或依赖进程ID就不安全了。这一点务必牢记
就是说保证id不被重用的唯一方法就是不关闭句柄.


那这就有疑问了,如果CloseHandle关闭了进程或者主线程句柄, 系统开新进程的id会使用原来的那个么?????
如果会,那不是乱套了,资源管理器里出现2个相同的进程的应用程序,
如过不会,那不是作者自己说的前后矛盾了.

请朋友们指点,谢谢。

...全文
308 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
Lactoferrin 2012-07-30
  • 打赏
  • 举报
回复
可以这么说,实际上大部分进程和线程创建后进程对象句柄数不止2,因为csrss也会打开它,而指针计数会更多,进程和线程刚创建时就会有个指针计数,此计数在接束后仍然在,直到某个系统工作线程执行PspReaper清理已结束的线程时进行一次解引用,它们占用的id至少保持到此时
wemvyen 2012-07-30
  • 打赏
  • 举报
回复
那也就是说父进程 CreateProcess()创建一个子进程, 代表这个子进程的进程对象的引用记数就会+2 ???

父进程CloseHandle(子进程句柄), 记数 -1
然后关闭自进程, 记数也 -1

是么????????
hotpos 2012-07-30
  • 打赏
  • 举报
回复
你销毁了句柄当然PID可能会回收 我说的是不销毁PID就不可能被回收。

你销毁了,还有人没销毁,PID就不会回收。

PID回收了,不一定立马就会用。

第一段的意思是
只有你销毁了你的句柄,PID才能被回收。
等所有人都把句柄销毁了,PID就被回收了。
因此你要是不用PID了,就把句柄销毁了,让系统回收。

第二段的意思是
你把句柄销毁了,PID就不安全了,可能会被回收。

如果你的句柄不是对象的最后一个句柄,销毁了PID还能用用。
如果你是最后一个,销毁了对象就回收了,PID就不安全了。
wemvyen 2012-07-30
  • 打赏
  • 举报
回复
不是的,你传个乱七八遭的数进去,不会异常的,只是返回FALSE

我怎么没看明白了啊,他书上就是这么写的啊,我一对比,发现矛盾了. 而且和你理解的不一致

你说 "进程退出, 你不关闭Handle,格式也不会回收,PID也不会回收。"

书上说 "但是,一旦调用了CloseHandle,再使用或依赖进程ID就不安全了" 说明一关handle,pid就可能被重用
hotpos 2012-07-30
  • 打赏
  • 举报
回复
断章取义
你根本没看明白。

crt异常是Windows防止你误删除两次而做的调试辅助功能。
wemvyen 2012-07-30
  • 打赏
  • 举报
回复
浅色字1的意思 -- 应该是建议大家创建子进程后,就用CloseHandle关闭子进程和主线程句柄
浅色字2的意思 -- 就是说保证id不被重用的唯一方法就是不关闭句柄.

那这就有疑问了,如果CloseHandle关闭了进程或者主线程句柄, 系统开新进程的id会使用原来的那个么?????
如果会,那不是乱套了,资源管理器里出现2个相同的进程的应用程序,
如过不会,那不是作者自己说的前后矛盾了.

同时

浅色字2意思,只要关闭了句柄, id就无效了,内核对象引用就减1了(当然内核对象本身不一定销毁)

我写代码做过试验的
CreateProcess(.....,&pi); 打开一个notepad.exe (没有手动按窗口X关闭)
然后立刻关闭句柄
ret1 = CloseHandle(pi.ThreadHandle);
ret2 = CloseHandle(pi.ProcessHandle);

ret1 ret2都是TRUE,也就是句柄成功销毁

如果按照书上说的, id就已经失效了,可以被重用 -- 这样的话, 就可能出现2个相同的id哦 ???


另外,
我还发现一个问题, 连续调用个关闭句柄2次,第2次的时候会引发crt异常,真奇怪
也就是这样写
ret1 = CloseHandle(pi.ThreadHandle);
ret2 = CloseHandle(pi.ProcessHandle);
ret1 = CloseHandle(pi.ThreadHandle); //<--crt异常,调试弹出非法框
ret2 = CloseHandle(pi.ProcessHandle); //<--crt异常,调试弹出非法框
按照以往的实际代码经验,句柄参数不管是NULL,还是乱七八遭的数据,只要内核找不到这个数值(即认为非法句炳), 则CloseHandle返回FALSE, 并不会异常的。
朋友们能解释下为什么会出现crt异常么, 谢谢了
hotpos 2012-07-30
  • 打赏
  • 举报
回复
WinXP的进程ID 是 进程对象在一个数组的下标 * 4(PID是4的倍数的原因)
Handle是进程对象的引用,增加一个Handle使对象的引用计数+1,相应的销毁一个Handle能使引用计数-1。
系统内核自己有一个进程对象的Handle,在进程退出后才会销毁。

占用PID其实就是占用了数组中的一个格子。


结论就是
你在用户模式能看到的句柄不会影响系统的句柄,但会影响对象的回收。


进程不退出,内核的Handle不会销毁,数组中的格子就不会被回收,PID也就不会回收。
进程退出, 你不关闭Handle,格式也不会回收,PID也不会回收。

上面的浅色子就明白了。
Lactoferrin 2012-07-30
  • 打赏
  • 举报
回复
如果进程没结束,就算所有进程都关闭了这个进程的句柄,它也不会消失
如果进程结束了,任务管理器里面就不会显示
所以不会出现你说的情况

15,466

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧