进程有下面5种正常终止方式:

(1)在main函数内执行return语句。这等效于调用exit。

(2)调用exit函数。此函数有ISO C定义,其操作包括调用各终止处理程序(终止处理程序在调用atexit函数时登记),然后关闭所有标准I/O流等。

(3)调用_exit或_Exit函数。ISO C定义_Exit,其目的是为进程提供一种无需运行终止处理程序或信号处理程序而终止的方法。对标准I/O流是否进行冲洗,这取决于实现。在UNIX系统中,_Exit和_exit是同义的,并不清洗标准I/O流。_exit函数由exit调用,它处理UNIX特定的细节。

在大多数UNIX系统实现中,exit(3)是标准C库中的一个函数,而_exit(2)则是一个系统调用。

(4)进程的最后一个线程在其启动例程中执行返回语句。但是,该线程的返回值不会用作进程的返回值。当最后一个线程从其启动例程返回时,该进程以终止状态0返回。

(5)进程的最后一个线程调用pthread_exit函数。在这种情况下,进程终止状态总是0,这与传送给pthread_exit的参数无关。

三种异常终止方式如下:

(1)调用abort。它产生SIGABRT信号,这是下一种异常终止的特例。

(2)当进程接收到某些信号时。信号可由进程自身(例如调用abort函数)、其他进程或内核产生。

(3)最后一个线程对“取消”(cancellation)请求作出响应。按系统默认,“取消”以延迟方式发生:一个线程要求取消另一个线程,一段时间之后,目标线程终止。

不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。

对于上述任意一种终止情形,我们都希望终止进程能够通知其父进程它是如何终止的。对于三个终止函数(exit、_exit和_Exit),实现这一点的方法是,将其退出状态(exit status)作为参数传递给函数。在异常终止情况下,内核(不是进程本身)产生一个指示其异常终止原因的终止状态(termination status)。在任意一种情况下,该终止进程的父进程都能用wait或waitpid函数取得其终止状态。

注意,这里使用了“退出状态”(它是传向exit或_exit的参数,或main的返回值)和“终止状态”两个术语,以表示有所区别。在最后调用_exit时,内核将退出状态转换成终止状态(回忆图7-1http://www.cnblogs.com/nufangrensheng/p/3507921.html)。如果子进程正常终止,父进程可以获得子进程的退出状态。

在说明fork函数时,显而易见,子进程是在父进程调用fork后生成的。上面又说了子进程将其终止状态返回给父进程。但是如果父进程在子进程之前终止,则将如何呢?其回答是:对于父进程已经终止的所有进程,它们的父进程都改变为init进程。我们称这些进程由init进程领养。其操作过程大致如下:在一个进程终止时,内核逐个检查所有活动进程,以判断它是否是正要终止进程的子进程,如果是,则将该进程的父进程ID更改为1(init进程的ID)。这种处理方法保证了每个进程都有一个父进程。

另一个我们关心的情况是如果子进程在父进程之前终止,那么父进程又如何能在做相应检查时得到子进程的终止状态呢?对此问题的回答是:内核为每个终止子进程保存了一定量的信息,所以当终止进程的父进程调用wait或waitpid时,可以得到这些信息。这些信息至少包括进程ID、该进程的终止状态、以及该进程使用的CPU时间总量。内核可以释放终止进程所使用的所有存储区,关闭其所有打开文件。在UNIX术语中,一个已经终止,但是其父进程尚未对其进行善后处理(使用wait获取终止子进程的有关信息,释放它仍占用的资源)的进程称为僵死进程(zombie)(更多关于僵尸进程可参考:http://www.cnblogs.com/bettercoder/p/3501086.html)。ps(1)命令将僵死进程的状态打印为Z。如果编写一个长期运行的程序,它调用fork产生了很多子进程,那么除非父进程等待取得子进程的终止状态,否则这些子进程终止后就会变成僵死进程。

最后一个要考虑的问题是:一个由init进程领养的进程终止时会发生什么?它会不会变成一个僵死进程?对此问题的回答是:“否”,因为init被编写成无论何时只要有一个子进程终止,init就会调用wait函数取得其终止状态。这样也就防止了在系统中有很多僵死进程。当提及“一个init的子进程”时,这指的可能是init直接产生的进程,也可能是其父进程已终止,由init领养的进程。

本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

进程控制之exit函数的更多相关文章

  1. 进程控制之fork函数

    一个现有进程可以调用fork函数创建一个新进程. #include <unistd.h> pid_t fork( void ); 返回值:子进程中返回0,父进程中返回子进程ID,出错返回- ...

  2. 进程控制之exec函数

    用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序.当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行.因为调用exec并不创 ...

  3. 2.5 进程控制之wait函数

    一.绪论 一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果 是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是 ...

  4. 【Linux编程】进程终止和exit函数

    内核要运行一个应用程序,唯一的途径是通过系统调用.exec函数.exec又会调用启动程序,启动程序(一般是汇编语言)以类似以下的方式调用main函数: void exit(main(argc, arg ...

  5. Linux系统编程_8_进程控制之fork_wait_waitpid函数

    fork函数: #include <unistd.h>        pid_t fork(void); fork用来创建一个子进程: 特点: fork调用后会返回两次,子进程返回0,父进 ...

  6. linux c编程:进程控制(三)_exec函数

    fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本,它将获得父进程数据空间.堆.栈等资源的副本.注意,子进程持有的是上述存储空间的“副本”,这意味着父子进 ...

  7. 进程控制之system函数

    ISO C定义了system函数,但是其操作对系统的依赖性很强.POSIX.1包括了system接口,它扩展了ISO C定义,以描述system在POSIX.1环境中的运行行为. #include & ...

  8. 进程控制之vfork函数

    vfork函数的调用序列和返回值与fork相同,但两者的语义不同. vfork用于创建一个新进程,而新进程的目的是exec一个新程序.vfork和fork一样都创建一个子进程,但是它并不将父进程的地址 ...

  9. 进程控制之waitid函数

    Single UNIX Specification的XSI扩展包括了另一个取进程终止状态的函数--waitid,此函数类似于waitpid,但提供了更多的灵活性. #include <sys/w ...

随机推荐

  1. 移动端rem布局

    手机页面——分辨率特别乱: 1.定宽320px——优点:简单,缺点:不能适应 2.百分比——优点:能适应各种分辨率,缺点:太麻烦 3.rem——优点:方便.适应各种分辨率(首先定义一个“根大小”htm ...

  2. 如果Apache Spark集群中没有分布式系统,则会?

    若当连接到Spark的master之后,若集群中没有分布式文件系统,Spark会在集群中每一台机器上加载数据,所以要确保Spark集群中每个节点上都有完整数据. 通常可以选择把数据放到HDFS.S3或 ...

  3. 细说OpenSessionInView问题

    [环境参数] 环境:SSH框架 [问题描述]  NoSession问题 HibernateTemplate对象提供的方法如果使用“延迟加载”,Session对象的管理不受开发者控制,此时如果在表现层获 ...

  4. [翻译]Behavior-Driven Development (BDD)行为驱动开发(二)

    测试驱动开发体现了开发人员对软件产品各部分运作方式的理解,而行为驱动开发则关注于开发人员对软件产品最终表现的行为的预期. 行为驱动开发 TDD更像是一种范式而不是一个过程.它描述了一种先编写测试,然后 ...

  5. HDU 2101 A + B Problem Too 分类: ACM 2015-06-16 23:57 18人阅读 评论(0) 收藏

    A + B Problem Too Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  6. C++11强类型枚举

    [C++11强类型枚举] 在标准C++中,枚举类型不是类型安全的.枚举类型被视为整数,这使得两种不同的枚举类型之间可以进行比较.C++03 唯一提供的安全机制是一个整数或一个枚举型值不能隐式转换到另一 ...

  7. HDU 4618 Palindrome Sub-Array (2013多校2 1008 暴力)

    Palindrome Sub-Array Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Oth ...

  8. 安装php5.5

    安装php5.5 ./configure --prefix=/usr/local/php5.5.14/ --with-apxs2=/usr/local/apache2.2.27/bin/apxs -- ...

  9. FZU 2129 子序列个数 (递推dp)

    题目链接:http://acm.fzu.edu.cn/problem.php?pid=2129 dp[i]表示前i个数的子序列个数 当a[i]在i以前出现过,dp[i] = dp[i - 1]*2 - ...

  10. Java中的多线程操作初探

    问题引出: 说是java,其实还是在做android的时候遇到的问题,在android 4.0以后,访问网络必须在新线程中实现,所以才会遇到这个问题.只是为了方面说明问题,才新建一个java项目.在m ...