子进程信号处理及wait waitpid区别

当一个进程正常或异常终止时,内核就向父进程发送SIGCHLD信号,因为子进程终止是个异步事件,可以在父进程运行的任何时候发生,所以这种信号也是内核向父进程发的异步通知,父进程可以选择忽略该信号,或者提供一个该信号发生时即被调用执行的函数(即信号处理程序),对于这种信号,系统的默认动作是忽略他。


二、wait

pid_t wait (int * status);

定义于 sys/wait.h头文件中,若成功则返回进程ID,若出错返回-1。


如果参数status不为空,则进程终止状态被保存于其中。

依据传统,返回的整形状态字是由实现定义的,其中有些位表示退出状态(正常返回),其他位表示信号编号(异常返回),有一位表示是否产生了一个core文件等。

终止状态是定义在 sys/wait.h中的各个宏,有四可互斥的宏可以用来取得进程终止的原因。


  • WIFEXITED           正常返回时为真,可以执行宏函数WEXITSTATUS获取子进程传送给exit、_exit或_Exit的参数的低8位

  • WIFSIGNALED         异常返回时为真,可以执行宏函数WTERMSIG取得子进程终止的信号编号,另外,对于一些实现,定义有宏WCOREDUMP宏,若以经昌盛终止进程的core文件,则为真

  • WIFSTOPPED          若为当前暂停子进程的返回的状态,则为真,可执行WSTOPSIG取得使子进程暂停的信号编号

  • WIFCONTINUED        若在作业控制暂停后已经继续的子进程返回了状态,则为真,仅用于waitpid


  7 #include "../apue.2e/include/apue.h"

  8 #include <sys/wait.h>

  9 

 10 void pr_exit (int status)

 11 {

 12         if (WIFEXITED(status))

 13                 printf ("normal termination, exit status = %d\n", WEXITSTATUS(status));

 14         else if (WIFSIGNALED(status))

 15                 printf ("abnormal termination, signal number = %d%s\n", WTERMSIG(status),

 16 #ifdef WCOREDUMP

 17         WCOREDUMP(status)?"(core file generated)":"");

 18 #else

 19         "");

 20 #endif

 21         else if (WIFSTOPPED(status))

 22                 printf ("child stopped, signal number = %d\n", WSTOPSIG(status));

 23 }

 24 

 25 int main ()

 26 {

 27         pid_t pid;

 28         int status;

 29 

 30         if ((pid = fork())<0)

 31                 err_sys ("fork error");

 32         else if (pid == 0)

 33                 exit (7);

 34         if (wait(&status) != pid)

 35                 err_sys ("wait error");

 36         pr_exit (status);

 37 

 38         if ((pid = fork())<0)

 39                 err_sys ("fork error");

 40         else if (pid == 0)

 41                 abort();

 42         if (wait(&status) != pid)

 43                 err_sys ("wait error");

 44         pr_exit (status);

 45 

 46         if ((pid = fork())<0)

 47                 err_sys ("fork error");

 48         else if (pid == 0)

 49                 status /= 0;

 50         if (wait(&status) != pid)

 51                 err_sys ("wait error");

 52         pr_exit (status);

 53 

 54         exit (0);

 55 }


运行结果如下:

normaltermination, exit status = 7

abnormaltermination, signal number = 6

abnormaltermination, signal number = 8


但是,6和8究竟指的是什么,并没有一种可移植的方法去说明,我们需要去查看signal.h头文件才能知道对应的宏的含义


三、waitpid

pid_t waitpid (pid_t pid, int * status, int options);

定义于 sys/wait.h头文件中,若成功则返回进程ID,0,若出错返回-1。


waitpid提供了wait更多的功能,基本用法于返回值与wait相同

1、pid参数

对于有多个子进程的父进程,只要有一个子进程终止,父进程中的wait函数就会返回,如果要等待特定的子进程,那就要不断的调用wait函数等待,POSIX定义了waitpid提供了等待特定子进程的功能及其他功能:waitpid的pid参数的作用:

  • pid== -1        等待任一子进程,wait的功能与此相同

  • pid> 0          等待进程ID为pid的子进程

  • pid== 0         等待组ID等于调用进程组ID的任一子进程

  • pid< -1         等待组ID等于-pid的任一子进程


waitpid函数返回终止子进程的进程ID,并将该子进程的终止状态存放在由status指针指向的空间中,如果指定的进程或进程组不存在,或者pid指定的进程不是调用进程的子进程,则调用失败返回-1。


2、options参数

当options参数为0时,与wait功能相同,不提供额外功能,如果为下列常量按位或则提供更多功能:


  • WCONTINUED      若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但状态尚未报告,则返回状态

  • WNOHANG         若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时返回0

  • WUNTRACED       若实现支持作业控制,而pid指定的任一子进程已经暂停,且其状态尚未报告,则返回其状态


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

  1. waitpid可以等待一个特定的进程,而wait则返回任一终止子进程的状态

  2. waitpid可以使父进程不进入阻塞状态

  3. waitpid支持作业控制


四、waitid

waitid 函数类似于 waitpid,但是提供了更多的灵活性


         int waitid (idtype_t idtype, id_t id, siginfo_t *infop, int options);

定义于 <sys/wait.h> 头文件中,调用成功返回0,否则返回-1


1、idtype 常量

  • P_PID     等待一个特定的进程:id参数包含要等待子进程的进程ID

  • P_PGID    等待一个特定进程组中的任一子进程:id参数包含要等待子进程的进程组ID

  • P_ALL     等待任一子进程,忽略id参数


2、options 常量

  • WCONTINUED     等待一个进程,他以前曾被暂停,此后又已继续,但其状态尚未报告

  • WEXITED        等待已退出的进程

  • WNOHANG        如果没有可用的子进程退出状态,立即返回而不是阻塞

  • WNOWAIT        不破坏子进程退出状态,该子进程退出状态可由后续的 wait、waitid 或 waitpid 调用取得

  • WSTOPPED       等待一个进程,他已经被暂停,但是其状态尚未报告


infop 参数是指向 siginfo 结构的指针,该结构包含了有关引起子进程状态改变的生成信号的详细信息

需要注意的是,UNIX 系统中只有 solaris 支持该函数

===============================================

wait及waitpid一个易混淆区别在于:

wait()只能处理一个子进程的SIGCHLD,如果多个并发子进程同事关闭,则会出现僵尸进程,而用waitpid()则会避免这种情况:如下
void sig_chld(int signo) 

      pid_t pid; 
      int stat; 

      while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) //非阻塞
          printf("child %d terminated\n", pid); 
      return; 
}

这段代码体现在当有多个子进程结束并几乎同时提交信号时,waitpid可使所有被提交的信号得到处理,而不会留下zombie。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值