Chinaunix首页 | 论坛 | 博客
  • 博客访问: 39287
  • 博文数量: 29
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 285
  • 用 户 组: 普通用户
  • 注册时间: 2014-12-08 13:03
个人简介

海纳百川有容乃大,壁立千仞无欲则刚。

文章分类
文章存档

2015年(17)

2014年(12)

我的朋友

分类: LINUX

2014-12-23 16:40:37

首先看一下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孙子进程将发生报错,代码如下:
  1. #include <sys/wait.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <stdio.h>
  5. #include <signal.h>
  6. #include <errno.h>

  7. #define STR "Name = %s, pid = %d, ppid = %d, pgid = %d\n"

  8. static void sig_usr(int signo)
  9. {
  10. }

  11. int main()
  12. {
  13.         pid_t pid;
  14.         int status;

  15.         if((pid = fork()) < 0)
  16.         {
  17.                 perror("fork B error");
  18.         }
  19.         else if(pid == 0)
  20.         {
  21.                 signal(SIGUSR1,sig_usr);
  22.                 sleep(1);
  23.                 printf(STR,"B",getpid(),getppid(),getpgrp());
  24.                 if((pid = fork()) < 0)
  25.                 {
  26.                         perror("fork D error");
  27.                 }
  28.                 else if(pid ==0)
  29.                 {
  30.                         signal(SIGUSR1,sig_usr);
  31.                         sleep(2);
  32.                         printf(STR,"D",getpid(),getppid(),getpgrp());
  33.                         sleep(99999999);
  34.                         return 68;
  35.                 }
  36.                 sleep(99999999);
  37.                 return 66;
  38.         }
  39.         printf(STR,"A",getpid(),getppid(),getpgrp());
  40.         sleep(5);
  41.         int id;
  42.         printf("Input wait pid:");
  43.         scanf("%d",&id);
  44.         if(waitpid(id,&status,0) == -1)
  45.         {
  46.                 perror("wait error");
  47.         }
  48.         else
  49.         {
  50.                 if(WIFEXITED(status))
  51.                 {
  52.                         printf("status = %d\n",WEXITSTATUS(status));
  53.                 }
  54.         }
  55.         return 65;
  56. }
[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不会返回。

例如我们使用以下代码创建一个后台进程

  1. #include <sys/wait.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <stdio.h>
  5. #include <signal.h>
  6. #include <error.h>

  7. int main()
  8. {
  9.    sleep(9999999);
  10.    return 0;
  11. }
[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的退出状态,代码如下:

  1. #include <sys/wait.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <stdio.h>
  5. #include <signal.h>
  6. #include <errno.h>

  7. #define STR "Name = %s, pid = %d, ppid = %d, pgid = %d\n"

  8. static void sig_usr(int signo)
  9. {
  10. }

  11. int main()
  12. {
  13.         pid_t pid;
  14.         int status;

  15.         if((pid = fork()) < 0)
  16.         {
  17.                 perror("fork B error");
  18.         }
  19.         else if(pid == 0)
  20.         {
  21.                 signal(SIGUSR1,sig_usr);
  22.                 sleep(1);
  23.                 if(setpgid(getpid(),31064) == -1)
  24.                         perror("setpgid error");
  25.                 printf(STR,"B",getpid(),getppid(),getpgrp());
  26.                 sleep(99999999);
  27.                 return 66;
  28.         }
  29.         if((pid = fork()) < 0)
  30.         {
  31.                 perror("fork C error");
  32.         }
  33.         else if(pid == 0)
  34.         {
  35.                 signal(SIGUSR1,sig_usr);
  36.                 sleep(2);
  37.                 printf(STR,"C",getpid(),getppid(),getpgrp());
  38.                 sleep(99999999);
  39.                 return 67;
  40.         }
  41.         printf(STR,"A",getpid(),getppid(),getpgrp());
  42.         sleep(5);
  43.         if(waitpid(0,&status,0) == -1)
  44.         {
  45.                 perror("wait error");
  46.         }
  47.         else
  48.         {
  49.                 if(WIFEXITED(status))
  50.                 {
  51.                         printf("status = %d\n",WEXITSTATUS(status));
  52.                 }
  53.         }
  54.         return 65;
  55. }

[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) |
给主人留下些什么吧!~~