子进程的异步等待方式

子进程:

子进程指的是由另一进程(对应称之为父进程)所创建的进程。   
子进程继承了对应的父进程的大部分属性,如文件描述符。在Linux中,子进程通常为系统调用fork的产物。在此情况下,子进程一开始就是父进程的副本,而在这之后,根据具体需要,子进程可以借助exec调用来链式加载另一程序。   
一个进程可能下属多个子进程,但最多只能有1个父进程,而若某一进程没有父进程,则可知该进程很可能由内核直接生成。在Linux与类Unix系统中,进程ID为1的进程(即init进程)是在系统引导阶段由内核直接创建的,且不会在系统运行过程中终止执行(可参见 Linux启动流程);而对于其他无父进程的进程,则可能是为在用户空间完成各种后台任务而执行的。另外,在对应的父进程结束执行后,进程就会变成孤儿进程,但之后会立即由init进程“收养”为其子进程。   
当某一子进程结束、中断或恢复执行时,内核会发送SIGCHLD信号予其父进程。在默认情况下,父进程会以SIG_IGN函数忽略之。   
某一子进程终止执行后,若其父进程未提前调用wait,则内核会持续保留子进程的退出状态等信息,以使父进程可以wait获取之 。而因为在这种情况下,子进程虽已终止,但仍在消耗系统资源,所以其亦称僵尸进程。wait常于SIGCHLD信号的处理函数中调用。

进程的几种状态:

static const char* const task_state_array[]
{
    "R(runing)",/*0*/
    "S(sleeping)",/*1*/
    "D(disk sleep)",/*2*/
    "T(stopped)",/*4*/
    "t(tract stop)",/*8*/
    "X(dead)",/*16*/
    "Z(zombie)",/*32*/
}

**深度睡眠状态(disk sleep)**D状态是深度睡眠状态,因为该进程在等待I/O资源,为了不被打断,则进入D状态,只有等到资源就绪后,才进入R状态

僵死状态(Zombies)一个比较特殊的状态。 指子进程结束运行(exit(0))后,系统将会保留子进程的描述符信息(没有被回收,其他进程不可以重用该描述符),当进程退出并且父进程(使用wait()系统调用)没有读取到子进程退出的返回代码时就会产生僵尸进程。僵尸进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
关于像是进程,可以参照Linux下僵尸进程与孤儿进程进行了解。

在产生僵尸进程后,父进程必须调用系统调用函数wait()或waitpid()对僵死的子进程进行等待,对子进程的残留信息进行清理,进程的等待方式分为阻塞方式非阻塞方式

那么wait()与waitpid()又是什么样的函数呢?

<1>wait 函数:

用来等待任何一个子进程退出,由父进程调用。

#include<sys/types.h>
#include<sys/wait.h>
pid_t  wait(int* status);

返回值:成功返回被等待子进程的pid,失败返回-1。
status:输出型参数,拿回子进程的退出信息。
wait:阻塞式调用,等待的子进程不退出时,父进程一直不退出。
目的:回收子进程,系统回收子进程的空间。

如果参数status不为空,则进程终止状态被保存于其中。
依据传统,返回的整形状态字是由实现定义的,其中有些位表示退出状态(正常返回),其他位表示信号编号(异常返回),有一位表示是否产生了一个core文件等。
终止状态是定义在 sys/wait.h中的各个宏,有四可互斥的宏可以用来取得进程终止的原因。

WIFEXITED:正常返回时为真,可以执行宏函数 WEXITSTATUS获取子进程传送给exit、_exit或_Exit的参数的低8位。
WIFSIGNALED :异常返回时为真,可以执行宏函数WTERMSIG取得子进程终止的信号编号,另外,对于一些实现,定义有宏WCOREDUMP宏,若以经昌盛终止进程的core文件,则为真。
WIFSTOPPED :若为当前暂停子进程的返回的状态,则为真,可执行WSTOPSIG取得使子进程暂停的信号编号。
WIFCONTINUED:若在作业控制暂停后已经继续的子进程返回了状态,则为真,仅用于waitpid。

<2>waitpid:

#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid,int* status,int options);

pid参数
从参数的名字pid和类型pid_t中就可以看出,这里需要的是一个进程ID。但当pid取不同的值时,在这里有不同的意义。
pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。
pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。

status参数与wait()函数的基本相同,此处不再赘述。

options参数
当options参数为0时,与wait功能相同,仍是阻塞式等待,不提供额外功能,如果为下列常量按位或则提供更多功能:
WCONTINUED:若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但状态尚未报告,则返回状态
WNOHANG:若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,即此时以非阻塞方式(轮询式访问的必要条件)等待子进程,并且返回0。
WUNTRACED:若实现支持作业控制,而pid指定的任一子进程已经暂停,且其状态尚未报告,则返回其状态

返回值:
当正常返回的时候,waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid就会出错返回,这时errno被设置为ECHILD;

waitpid提供了三个wait所没有的功能:

  1. waitpid可等待一个特定的进程
  2. waitpid提供了一个wait的非阻塞版本
  3. waitpid支持作业控制
 #include<stdio.h> 
 #include<stdlib.h> 
 #include<signal.h> 
 #include<unistd.h> 
 #include<sys/types.h> 

 void handler(int sig) 
 { 
     printf("father is catching,child is quit\n"); 
 } 
 int main() 
 { 
     signal(SIGCHLD,handler); 
     pid_t pid = fork(); 
     if(pid == 0)//child 
     { 
         printf("child:my pid is %d\n",getpid()); 
         sleep(2); 
         exit(-1);//子进程异常终止 
     } 
     else
     {
         while(1) 
         { 
             printf("father is doing something...\n"); 
             sleep(1); 
         } 
     }

     return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值