在《通过进程名字关闭进程》和《通过进程的ID关闭进程》文章中,已经有朋友介绍过TerminateProcess函数的使用。在此,只是作为一个补充,谈谈函数使用中需要注意的一些很重要的细节。
    TerminateProcess用来终止进程,可以是系统中的任何进程,只要知道进程的句柄,就可以终止。不过,强制终止进程,会导致一些问题。强制终止进程,进程并没有提前得到通知,而是突然就被击毙身亡,来不及写任何“遗嘱”就离开了计算机。这也就是在任务管理器强制关闭Word后,Word根本就不知道自己突然被终止了,正在编辑的内容来不及回写到硬盘保存就死去了,因此我们写的文章就烟消云散了。一般情况,我们是不会使用这个函数来终止进程的。
    不过,不用担心进程强制终止后进程的资源永远释放不了。这是操作系统的事情。操作系统检测到一个进程终止后,将会将这个进程相关的资源全部释放掉。因此不会存在资源泄露的问题。不过,释放资源并不是简单的删除释放。这一点需要特别清楚,这是Windows的机制,如果不理解将会有很多困惑。
    释放资源,在系统里,更确切的描述是递减资源引用计数。真正的删除资源,是由操作系统来执行的。每次有一个进程打开一个内核对象时,系统将给这个对象的引用计数递增一次,表示有一个进程在使用这个内核对象。进程关闭时,将释放这个内核对象的资源,而进程所做的操作便是释放引用,调用CloseHandle函数来释放对内核对象引用,在函数内部则是递减内核对象的引用计数。如果这个计数递减到了0,那么系统将会删除这个资源。因为计数为0后,表示不再有任何进程使用这个资源,也就没有必要存在,也就可以安全删除了。这里要注意,有时在编程时,忘记了释放资源,也就是忘记了调用CloseHandle函数,然后进程关闭了,导致这个资源一直都释放不了,即使你的进程已经关闭。这些资源,系统都认为是全局的。第一个进程可以使用,第二个也可以使用,这个机制是资源共享的方式。有些程序框架也借鉴这种机制来同步进程和共享资源。如果忘记了递减,则导致资源永远释放不了,也就为后面的逻辑造成了障碍,使后面的操作永远无法执行;而如果忘记了递增,那么程序也会出现逻辑陷入提前将资源释放导致问题,严重时导致指针悬空,出现内存访问错误,最严重时就是导致蓝屏。
    还要注意一点,TerminateProcess终止进程并不是同步执行的。也就是说,这个函数执行完后,就立马返回。它只是跟系统打了个招呼,说它要强行终止某一个进程,可能是自己的子进程,也可能是其他进程。用专业术语表示就是“异步执行”的。所以不要以为执行了这个函数,要强制终止的进程就终止了。所以这里要特别小心。这是进程间同步的一个问题。开始接触的朋友很容易犯错。
    所以,如果你想实现关闭一个进程后再根据进程关闭后的状态来做其他事情,或者说这个进程和自己的进程都做哦操作同一个共享的变量,那么需要先判断这个进程现在是否已经终止,如果没终止,那它还可能会修改这个公共变量,从而导致逻辑错误。这个是初学者所容易忽略的。
    判断一个进程是否终止,需要使用进程同步的相关函数。最常用的是WaitForSingleObject函数来等待信号,并将被强制终止的进程的句柄传进去。如果等待到了信号,说明进程句柄已经没有使用了,表示进程已经关闭,你可以继续执行,否则需要等待。
    WaitForSingleObject函数的具体使用,请参考本站的其他文章,或者查看MSDN详细了解。