Chinaunix首页 | 论坛 | 博客
  • 博客访问: 559106
  • 博文数量: 142
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1452
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-12 16:28
文章分类

全部博文(142)

文章存档

2016年(10)

2015年(60)

2014年(72)

我的朋友

分类: C/C++

2014-09-04 13:14:37

当一个进程正常或者异常终止时,内核就会向该进程的父进程发送SIGCHLD信号。父进程可以选择忽略该信号,或者提供一个信号处理函数。对于这种信号的系统默认动作时忽略它。
而wait和waitpid就是用来获取进程的退出状态的。
函数原型:
#include
pid_t wait(int *status);
1)若成功返回进程ID
2)若出错则返回-1.
     出错原因:1.调用进程没有子进程了;2.被信号中断

pid_t waitpid(pid_t pid, int *status, int options);
waitpid返回值:
1)若成功返回进程ID,
2)若出错则返回-1,
出错原因:1.子进程都不存在了;2.指定的进程或进程组不存在;3.指定的pid不是调用进程的子进程。4.信号中断。
3)如果指定选项WNOHANG并且有一个或多个由pid指定的子进程存在,但是没有状态变化,返回0。

这两个函数的参数status是一个整形指针。某些位表示正常返回,某些位表示异常退出,有一位表示是否产生了core文件。用宏定义来表示:
说明
WIFEXITED(status) 若为正常终止子进程返回的状态,则为真。对于这种情况可执行WEXITSTATUS(status)来获取返回值,取子进程传送给exit、_exit或_Exit参数的低8位
WIFSIGNALED(status) 若为异常终止子进程返回的状态,则为真(收到一个不捕捉的信号)。此时,可执行WTERMSIG(status),来获取子进程终止的信号编号。有些实现定义了宏WCOREDUMP(status),若已经产生终止进程的core文件,则它返回真。
WIFSTOPPED(status) 若为当前暂停子进程的返回的状态,则为真。对于这种情况,可执行WSTOPSIG(status),获取使子进程暂停的信号编号。
WIFCONTINUED(status) 若在作业控制暂停后已经继续的子进程返回了状态,则为真。
wait for (previously stopped) children that have been resumed by delivery of SIGCONT.

waitpid函数中的pid参数的作用:
pid
作用
-1 等待任一子进程。就这一方面而言,waitpid与wait等效,当然waitpid还有option选项
>0 等待进程ID与pid相等的子进程
0 等待其组ID等于调用进程组ID的任一子进程
<-1 等待其组ID等于pid绝对值的任一子进程

options参数进一步控制waitpid的操作,options可以为0,也可以是下表中的参数
常量 说明
WCONTINUED 若是实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但其状态尚未报告,则返回其状态。
即先kill -SIGSTOP  pid, 再kill -s SIGCONT pid ,后waitpid才返回。单独的kill -SIGSTOP pid,waitpid不会返回。

WNOHANG 若有pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0
WUNTRACED 若是实现支持作业控制,一个子进程处于暂停状态,并且其状态自暂停以来还没报告过,则返回其状态。WIFSTOPPED宏确定返回值是否对应于一个暂停子进程。
kill -SIGSTOP pid 后,waitpid就返回。

WCONTINUED和WUNTRACED组合后,kill -s SIGSTOP会返回,kill -s SIGSTOP pid后的kill -s SIGCONT pid也会返回。

waitpid提供了wait不支持的三个功能:
1.waitpid可等待一个特定的进程,而wait只等待第一个终止进程的状态
2.waitpid提供了不阻塞的wait版本。有时候用户希望取得一个子进程的状态,但不想阻塞。
3.waitpid支持作业控制(利用WUNTRACED和WCONTINUED)

实例一:
1. fork产生一个子进程,子进程pause等待,父进程注册SIGCHLD信号处理函数,停在while循环中等待处理子进程的SIGCHLD信号。
2.在信号处理函数中使用waitpid(-1,&status,0)---------- pid=-1表示等待任一子进程结束,option为0是默认没有特殊选项,
  此时waitpid的作用和wait(&status)一样,即阻塞等待任一子进程结束而退出。

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <signal.h>

  5. static void print_status(int status)
  6. {
  7.     if(WIFEXITED(status)) {
  8.         printf("normal termination status=%d\n",WEXITSTATUS(status));
  9.     }else if(WIFSTOPPED(status)) {
  10.         printf("signal stoped status=%d,status1=%d\n",WEXITSTATUS(status),WSTOPSIG(status));
  11.     }else if(WIFSIGNALED(status)) {
  12.         printf("signal termination status=%d,status1=%d\n",WEXITSTATUS(status),WTERMSIG(status));
  13.     }else if(WIFCONTINUED(status)) {
  14.         printf("signal continued\n");
  15.     }
  16. }

  17. static void sig_chld(int signo)
  18. {
  19.     int ret,status;

  20.     printf("entering sig_chld\n");
  21.     ret = waitpid(-1,&status,0);

  22.     printf("after wait........ ret=%d\n",ret);

  23.     print_status(status);
  24. }

  25. int main()
  26. {
  27.     pid_t pid;
  28.     int status=0;

  29.     pid = fork();

  30.     if(pid < 0)
  31.         perror("fork error");
  32.     else if(pid == 0){ /*child*/
  33.         printf("child id = %d,parent=%d\n",getpid(),getppid());
  34.         pause();
  35.     }else{ /*parent*/
  36.         if(signal(SIGCHLD,sig_chld) == SIG_ERR)
  37.             printf("signal(SIGCHLD) error\n");
  38.         while(1) {
  39.             sleep(1);
  40.         }
  41.     }
  42.     return 0;
  43. }
编译运行:
gwwu@hz-dev2.wgw.com:~/test/process>./a
child id = 5523,parent=5522-------------------子进程阻塞在pause(),父进程阻塞在while语句。
开启另一个窗口,使用命令kill -SIGSTOP 5523,只打印如下信息:
gwwu@hz-dev2.wgw.com:~/test/process>./a
child id = 5523,parent=5522
entering sig_chld---------------------可见此时父进程阻塞在了waitpid函数了,就是说wait函数对SIGSTOP信号并不退出。

接着kill -SIGCONT 5523 恢复被暂停的进程,
然后kill -8 5523
此时打印信息如下:
gwwu@hz-dev2.wgw.com:~/test/process>./a
child id = 5523,parent=5522
entering sig_chld
after wait........ ret=5523------------------------此时因为有子进程终止,所以父进程在原来的waitpid处阻塞被唤醒,进程本来就可以直接调用waitpid,而不需要信号,需要信号是防止进程太忙
signal termination status=0,status1=8
entering sig_chld---子进程又发送了一次SIGCHLD信号,调用waitpid,此时由于没有任何子进程了,所以waitpid不会阻塞了。
after wait........ ret=-1
signal termination status=0,status1=8

打印了两边,原因是kill -8 5523时,原来的父进程阻塞在waitpid,此时waitpid往下走,打印一次,然后kill命令又使得子进程发送了一次SIGCHLD信号,父进程再次处理,所有又从entering 出重新打印了。

实例二:
将waitpid(-1,&status,0)改为waitpid(-1,&status,WUNTRACED | WCONTINUED)
编译运行:
gwwu@hz-dev2.wgw.com:~/test/process>./a
child id = 6742,parent=6741-------子进程阻塞在pause(),父进程阻塞在while语句。
entering sig_chld---------收到kill -SIGSTOP 6742信号
after wait........
signal stoped status=19,status1=19
entering sig_chld-----------收到kill -SIGCONT 6742信号
after wait........
signal continued
entering sig_chld-----------收到kill -7 6742信号
after wait........
signal termination status=0,status1=7

可见对于SIGSTOP/SIGCONT必须是在waitpid下,并且option选项必须指定WUNTRACED | WCONTINUED,这时waitpid函数才会退出。


阅读(697) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~