对“托盘中的程序退出后,任务管理器中还能找该进程”研究分析
发现问题的经过:
公司开发的 windows 程序在启动运行时,在右下角的托盘里右键程序图标退出后,在重新启动程序后,因为防多次启动机制(锁原理),会提示该程序已经在运行中
但是托盘里已经找不到程序的图标,并且任务管理器的进程选项卡也无法找到,最终在任务管理器的详细信息选项卡中找到了该进程,强制结束后再启动程序,一切正常
问题分析:
主线程退出了,但是一些子线程还未完全退出,处于与硬件交互状态,导致程序还处于挂起状态;也可能是主线程也并未完全退出,这个有待研究
类似的讨论贴:程序退出后,进程还在 怎么处理???
有关这种问题的专业解析:
摘自 Raymond Chen 的 《Windows 编程启示录》第 19.6 小节
为什么有些进程在被终止之后还停留在任务管理器中?
当某个进程结束时(可能是正常结束,也可能是因为调用了像 TerminateProcess 之类的函数),这个进程的用户态模块将被删除。但内核态模块只有在与线程相关的所有驱动程序执行完成之后才会被删除。
例如,如果某个线程正处于 I/O 操作中,那么将会给负责 I/O 的驱动程序发送一个内核信号来取消这个操作。如果驱动程序的行为是良好的,那么它将清除与这个未完成 I/O 相关的一些信息并且释放线程。
如果驱动程序的行为是不好的(可能是因为驱动程序管理的硬件表现出奇怪的行为),那么可能需要花很长的时间来清除这个未完成的 I/O。在这段时间里,驱动程序将不会释放这个线程(以及这个线程所在
的进程)。实际的情况要更复杂一些,但这里的简单模型对于我们的讨论已经足够。
调试内核的程序员请注意:如果你认为问题在于某个驱动程序,那么可以进入到内核调试器中,找到这个停顿的进程,看看为什么其中的线程没有退出。你可以用 ! irp 调试命令来查看所有未决的 IRP(I/O 请求包),
这样就可以知道究竟是什么设备没有完成操作。
当所有的驱动程序都执行完了相应的操作,这个进程才会最终消失。而进程对象将会被保留下来,直到所有指向进程的句柄和进程中的所有线程都被关闭了才会消失(你一定不要忘记调用 CloseHandle 函数来关闭在
PROCESS_INFORMATION 结构中返回的句柄,这个结构是在调用 CreateProcess 函数时传递的参数之一)。
换句话说,如果当你终止了某个进程后还能在任务管理器中看到这个进程,那么实际上这个进程已经停止运行了,只不过还有些残留的信息保留在系统中,只有当与这个进程相关的所有驱动程序都完成了清除操作
并且所有指向这个进程的句柄都已经关闭,进程才会完全消失。