当一个进程正常或者异常终止时,内核就会向该进程的父进程发送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)一样,即阻塞等待任一子进程结束而退出。
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <signal.h>
-
-
static void print_status(int status)
-
{
-
if(WIFEXITED(status)) {
-
printf("normal termination status=%d\n",WEXITSTATUS(status));
-
}else if(WIFSTOPPED(status)) {
-
printf("signal stoped status=%d,status1=%d\n",WEXITSTATUS(status),WSTOPSIG(status));
-
}else if(WIFSIGNALED(status)) {
-
printf("signal termination status=%d,status1=%d\n",WEXITSTATUS(status),WTERMSIG(status));
-
}else if(WIFCONTINUED(status)) {
-
printf("signal continued\n");
-
}
-
}
-
-
static void sig_chld(int signo)
-
{
-
int ret,status;
-
-
printf("entering sig_chld\n");
-
ret = waitpid(-1,&status,0);
-
-
printf("after wait........ ret=%d\n",ret);
-
-
print_status(status);
-
}
-
-
int main()
-
{
-
pid_t pid;
-
int status=0;
-
-
pid = fork();
-
-
if(pid < 0)
-
perror("fork error");
-
else if(pid == 0){ /*child*/
-
printf("child id = %d,parent=%d\n",getpid(),getppid());
-
pause();
-
}else{ /*parent*/
-
if(signal(SIGCHLD,sig_chld) == SIG_ERR)
-
printf("signal(SIGCHLD) error\n");
-
while(1) {
-
sleep(1);
-
}
-
}
-
return 0;
-
}
编译运行:
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) |