首先看一下APUE中的定义:
对于waitpid函数中pid参数的作用解释如下:
pid == -1 等待任一子进程,就这方面而言,waitpid与wait等效
pid > 0 等待其进程ID与pid相等的子进程
pid ==0 等待其组ID等于调用进程组ID的任一子进程
pid < -1 等待其组ID等于pid绝对值的任一子进程
再来看一下waitpid出错的原因
1. 如果指定的进程或进程组不存在
2. 参数pid指定的进程不是调用进程的子进程则都将出错
首先需要明确的的是,waitpid方法只能获取到子进程的终止状态。不管pid为哪一类值,其首要条件就是必须为调用进程的子进程。以下几类都会返回-1:
1. pid > 0, pid 为其他进程的ID,不是调用waitpid函数的子进程
2. pid > 0, pid为调用进程的子进程的子进程(孙子进程)
waitpid孙子进程将发生报错,代码如下:
-
#include <sys/wait.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <signal.h>
-
#include <errno.h>
-
-
#define STR "Name = %s, pid = %d, ppid = %d, pgid = %d\n"
-
-
static void sig_usr(int signo)
-
{
-
}
-
-
int main()
-
{
-
pid_t pid;
-
int status;
-
-
if((pid = fork()) < 0)
-
{
-
perror("fork B error");
-
}
-
else if(pid == 0)
-
{
-
signal(SIGUSR1,sig_usr);
-
sleep(1);
-
printf(STR,"B",getpid(),getppid(),getpgrp());
-
if((pid = fork()) < 0)
-
{
-
perror("fork D error");
-
}
-
else if(pid ==0)
-
{
-
signal(SIGUSR1,sig_usr);
-
sleep(2);
-
printf(STR,"D",getpid(),getppid(),getpgrp());
-
sleep(99999999);
-
return 68;
-
}
-
sleep(99999999);
-
return 66;
-
}
-
printf(STR,"A",getpid(),getppid(),getpgrp());
-
sleep(5);
-
int id;
-
printf("Input wait pid:");
-
scanf("%d",&id);
-
if(waitpid(id,&status,0) == -1)
-
{
-
perror("wait error");
-
}
-
else
-
{
-
if(WIFEXITED(status))
-
{
-
printf("status = %d\n",WEXITSTATUS(status));
-
}
-
}
-
return 65;
-
}
[huenyifei@localhost test]$ ./waitpid
Name = A, pid = 30802, ppid = 4992, pgid = 30802
Name = B, pid = 30803, ppid = 30802, pgid = 30802
Name = D, pid = 30805, ppid = 30803, pgid = 30802
Input wait pid:30803
在另一个窗口输入:kill -USR1 30803
[huenyifei@localhost test]$ ./waitpid
Name = A, pid = 30802, ppid = 4992, pgid = 30802
Name = B, pid = 30803, ppid = 30802, pgid = 30802
Name = D, pid = 30805, ppid = 30803, pgid = 30802
Input wait pid:30803
status = 66
结果正常,如果我们等待孙子进程,则报错,如下:
[huenyifei@localhost test]$ ./waitpid
Name = A, pid = 30870, ppid = 4992, pgid = 30870
Name = B, pid = 30871, ppid = 30870, pgid = 30870
Name = D, pid = 30872, ppid = 30871, pgid = 30870
Input wait pid:30872
wait error: No child processes
只有搞清楚了以上内容才能明白 pid 的4中类型所涵盖的范围。如果我们使用pid==0,但是调用进程的一个子进程的PGID却和调用进程不一样,这时waitpid不会返回。
例如我们使用以下代码创建一个后台进程
-
#include <sys/wait.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <signal.h>
-
#include <error.h>
-
-
int main()
-
{
-
sleep(9999999);
-
return 0;
-
}
[huenyifei@localhost test]$ gcc sleep.c -o sleep
[huenyifei@localhost test]$ ./sleep &
[1] 31064
之后,我们创建进程A,A fork 进程B B调用setpgid将自己加入 进程组 31064,A继续创建一个进程C。此时B为A的子进程,但是并不属于进程A的进程组,如果我们结束进程B,A并不会得到B的退出状态,代码如下:
-
#include <sys/wait.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <signal.h>
-
#include <errno.h>
-
-
#define STR "Name = %s, pid = %d, ppid = %d, pgid = %d\n"
-
-
static void sig_usr(int signo)
-
{
-
}
-
-
int main()
-
{
-
pid_t pid;
-
int status;
-
-
if((pid = fork()) < 0)
-
{
-
perror("fork B error");
-
}
-
else if(pid == 0)
-
{
-
signal(SIGUSR1,sig_usr);
-
sleep(1);
-
if(setpgid(getpid(),31064) == -1)
-
perror("setpgid error");
-
printf(STR,"B",getpid(),getppid(),getpgrp());
-
sleep(99999999);
-
return 66;
-
}
-
if((pid = fork()) < 0)
-
{
-
perror("fork C error");
-
}
-
else if(pid == 0)
-
{
-
signal(SIGUSR1,sig_usr);
-
sleep(2);
-
printf(STR,"C",getpid(),getppid(),getpgrp());
-
sleep(99999999);
-
return 67;
-
}
-
printf(STR,"A",getpid(),getppid(),getpgrp());
-
sleep(5);
-
if(waitpid(0,&status,0) == -1)
-
{
-
perror("wait error");
-
}
-
else
-
{
-
if(WIFEXITED(status))
-
{
-
printf("status = %d\n",WEXITSTATUS(status));
-
}
-
}
-
return 65;
-
}
[huenyifei@localhost test]$ ./waitpid
Name = A, pid = 31227, ppid = 4992, pgid = 31227
Name = B, pid = 31228, ppid = 31227, pgid = 31064
Name = C, pid = 31229, ppid = 31227, pgid = 31227
在另一窗口执行:kill -USR1 31228
[huenyifei@localhost test]$ ps -ae|grep waitpid
31227 pts/1 00:00:00 waitpid
31228 pts/1 00:00:00 waitpid
31229 pts/1 00:00:00 waitpid
可以看到, 进程B已经变为僵尸进程,但是进程A仍然阻塞在waitpid中。
最后,需要指出的是关于pid < -1,此时传入的pid可以为任何进程组,只要保证该进程组中存在调用waitpid进程的子进程即可。
阅读(2771) | 评论(0) | 转发(0) |