Windows viaC/C++:终止进程

原创 2013年12月02日 14:34:14

结束进程

进程可以以4种方式结束:

  • 主线程入口点函数(_tmain/_tWinMain)返回时结束,建议所有进程都以这种方式结束
  • 进程中的某线程调用了ExitThread函数,应当避免这种情况
  • 另一进程中的某线程调用了TerminateProcess函数,应当避免这种情况
  • 进程中的所有线程中止,这种情况比较罕见

下面我们来分别讨论这4种情形。

 

主线程入口点函数返回

在设计应用程序时,你应该保证其进程只有在主线程入口点函数返回时才终止,这也是确保能够正确释放主线程使用的所有资源的唯一途径。主线程入口点函数正常返回时,系统将会执行下面的动作:

  • 主线程创建的所有C++对象将被正确的销毁
  • 主线程堆栈占用的内存空间将被释放
  • 系统会把入口点函数的返回值作为进程的退出码写入进程内核对象中
  • 进程/主线程内核对象引用计数减1

调用ExitProcess函数

当进程中的任意线程调用ExitProcess函数时,进程将被终止。我们在前面的章节提过,C/C++运行时启动函数在主线程入口点函数(WinMain、wWinMain、main或wmain)返回时,会清理进程使用的所有C运行时资源,然后显式调用ExitProcess,并将入口点函数的返回值传给ExitProcess。这也解释了主线程入口点函数返回会导致进程中止的原因,注意此时进程中的所有线程也会随进程一起终止。

根据Windows PlatformSDK文档的说法,当进程中仍然有线程在执行时,进程不会终止。对于操作系统而言这是正确的,可是C/C++运行时的实现却并非如此:当主线程入口点函数返回时,无法有进程中是否有其它正在执行的线程,进程都会被ExitProcess函数终止。然而如果你在入口点函数中调用了ExitThread而不是将其返回或调用ExitProcess,主线程会停止执行,但进程会一直存在直到其中最后一个线程中止。

调用ExitThread和ExitProcess会导致线程或进程在函数内立刻终止,对于操作系统来说这无关紧要,因为系统会保证释放线程/进程用到的系统资源,但是,C/C++程序应该避免调用这些函数,C/C++运行时可能无法及时执行清理工作,比如下面的代码:

  1. #include   
  2. #include   
  3.   
  4. class CSomeObj  
  5. public 
  6.    CSomeObj()  printf("Constructor/r/n");  
  7.    ~CSomeObj() printf("Destructor/r/n");  
  8. };  
  9.   
  10.   
  11. CSomeObj g_GlobalObj;  
  12.   
  13. void main ()  
  14.    CSomeObj LocalObj;  
  15.    ExitProcess(0);    // This shouldn't be here  
  16.   
  17.    // At the end of this function, the compiler automatically added  
  18.    // the code necessary to call LocalObj's destructor.  
  19.    // ExitProcess prevents it from executing.  
  20.  
#include class CSomeObj { public: CSomeObj() {printf("Constructor/r/n"); } ~CSomeObj() {printf("Destructor/r/n"); } }; CSomeObj g_GlobalObj; void main () {CSomeObj LocalObj; ExitProcess(0); // This shouldn't be here // Atthe end of this function, the compiler automatically added // thecode necessary to call LocalObj's destructor. // ExitProcessprevents it from executing.}  执行上面的代码时,输出如下:
  1. Constructor  
  2. Constructor  
 代码创建了两个对象,一个全局对象一个局部对象。然而,ExitProcess的调用导致对象没有被正确的析构,在移除ExitProcess之后,程序输出正常结果:
  1. Constructor  
  2. Constructor  
  3. Destructor  
  4. Destructor  
  

调用TerminateProcess函数

TerminateProcess也会导致进程中止:

  1. BOOL TerminateProcess(HANDLE hProcess, UINT fuExitCode);  
  与ExitProcess最大的不同在于,TerminateProcess除了可以中止当前进程,还可以中止其它进程。参数hProcess指定了要终止的进程句柄,其退出码由fuExitCode指定。当你无法使用别的方法结束某进程时,你才应该调用TerminateProcess。被结束的进程不会得到任何关于它将被终止的通知,它也没机会做任何清理工作。然而进程用到的系统资源将被系统释放,记住,当进程终止时,它用到的一切资源都会回收。TerminateProcess是异步方法,这意味着它返回时目标进程可能尚未被终止,因此你可能需要调用WaitForSingleObject等待其结束。

所有线程中止

当进程内的所有线程终止时,操作系统将销毁进程地址空间,进程的退出码将被设置为最后一个线程的退出码。

进程终止时发生了什么

当进程终止时,下面的动作会被触发:

  • 进程内的所有线程将被终止
  • 进程创建的所有的用户对象和GUI对象将被释放,其引用的所有内核对象引用计数减1
  • 进程的退出码从STILL_ACTIVE变为ExitProcess或TerminateProcess函数的相应参数
  • 进程的内核对象状态变成signaled(关于内核对象状态,可参阅第9章)
  • 进程的内核对象引用计数减1

 

注意进程内核对象的生命周期和进程的生命周期并不完全相同,进程终止只是将其内核对象的引用计数减1,如果此时另外的进程仍持有该对象的句柄,那么进程内核对象并不会销毁。这通常发生在父进程忘记关闭子进程的句柄时,这是一个特性,而不是BUG。进程内核对象维护着进程的统计信息,这些信息在进程终止之后依然是可用的。比如,你可以获得进程占用的CPU时间总数,或者用GetExitCodeProcess获得其退出码:

  1. BOOL GetExitCodeProcess(HANDLE hProcess, PDWORD pdwExitCode);  
  当目标进程尚未结束时,GetExitCodeProcess的pdwExitCode会返回STILL_ACTIVE,否则返回其退出码。你可能会想到可以在一个循环中使用GetExitCodeProcess以判断某进程是否结束,这的确可以,不过显然效率比较低,在下一节我会提到一种更恰当的判断进程是否结束的方法。

再说一遍,当你对进程的统计信息不再感兴趣时,要记得调用CloseHandle关闭内核对象句柄,否则进程内核对象会一直存在。

相关文章推荐

Windows线程创建、退出及资源释放

可以通过以下几种方法创建一个线程: 1、CreateThread 2、_beginthread 3、_beginthreadex 4、AfxBeginThread -------------...
  • xwdpepsi
  • xwdpepsi
  • 2013年10月07日 11:08
  • 13038

[经验总结]Windows中关闭进程的C++实现

// [Added by thinkhy 09/12/20]// Description: Kill process(es) by PID.// Reference: http://www.vck...
  • ThinkHY
  • ThinkHY
  • 2009年12月20日 21:56
  • 5130

给定A, B两个整数,不使用除法和取模运算,求A/B的商和余数

给定A, B两个整数,不使用除法和取模运算,求A/B的商和余数。 1.   最基本的算法是,从小到大遍历: for (i = 2 to A -1)          if (i * B > A)...

利用K-means聚类算法根据经纬度坐标对中国省市进行聚类

K-means聚类算法是一种非层次聚类算法,在最小误差的基础上将数据划分了特定的类,类间利用距离作为相似度指标,两个向量之间的距离越小,其相似度就越高。程序读取全国省市经纬度坐标,然后根据经纬度坐标进...

Radon变换理论介绍与matlab实现--经验交流

本人最近在研究Radon变换,在查阅了各种资料之后在此写下个人的理解,希望与各位牛牛进行交流共同进步,也使得理解更加深刻些。 Radon变换的本质是将原来的函数做了一个空间转换,即,将原来的XY平...

Matlab绘图-很详细,很全面

Matlab绘图强大的绘图功能是Matlab的特点之一,Matlab提供了一系列的绘图函数,用户不需要过多的考虑绘图的细节,只需要给出一些基本参数就能得到所需图形,这类函数称为高层绘图函数。此外,Ma...

CT图像重建技术

由于csdn贴图不方便,并且不能上传附件,我把原文上传到了资源空间CT图像重建技术 1.引言 计算机层析成像(Computed Tomography,CT)是通过对物体进行不同角度的射线投影测量而...

linux查找目录下的所有文件中是否含有某个字符串

查找目录下的所有文件中是否含有某个字符串  find .|xargs grep -ri "IBM"  查找目录下的所有文件中是否含有某个字符串,并且只打印出文件名  find .|xargs g...

Radon变换入门matlab CT原理

http://hi.baidu.com/hi9394/blog/item/0d492b8bfd714700c8fc7aa9.html 简介 图像投影,就是说将图像在某一方向上做线性积分(或理解为累...

Intel系列处理器的三种工作模式

Intel系列处理器的三种工作模式 微机中常用的Intel系列微处理器的主要发展过程是:8080,8086/8088,80186, 80286,80386,80486,Pentium,Pen...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Windows viaC/C++:终止进程
举报原因:
原因补充:

(最多只允许输入30个字)