写点什么

Android C++ 系列:Linux 进程 (三)

作者:轻口味
  • 2021 年 11 月 23 日
  • 本文字数:1564 字

    阅读完需:约 5 分钟

Android C++系列:Linux进程(三)

wait/waitpid

僵尸进程: 子进程退出,父进程没有回收子进程资源(PCB),则子进程变成僵尸进程


孤儿进程: 父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为 1 号 进程 init 进程,称为 init 进程领养孤儿进程


#include <sys/types.h> #include <sys/wait.h>pid_t wait(int *status);pid_t waitpid(pid_t pid, int *status, int options);
复制代码


  • < -1 回收指定进程组内的任意子进程

  • -1 回收任意子进程

  • 0 回收和当前调用 waitpid 一个组的所有子进程 > 0 回收指定 ID 的子进程


一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的 PCB 还 保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止 则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用 wait 或 waitpid 获取这 些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态可以在 Shell 中用特殊变 量 $?查看,因为 Shell 是它的父进程,当它终止时 Shell 调用 wait 或 waitpid 得到它的退出状 态同时彻底清除掉这个进程。


如果一个进程已经终止,但是它的父进程尚未调用 wait 或 waitpid 对它进行清理,这时 的进程状态称为僵尸(Zombie)进程。任何进程在刚终止时都是僵尸进程,正常情况下,僵 尸进程都立刻被父进程清理了,为了观察到僵尸进程,我们自己写一个不正常的程序,父进 程 fork 出子进程,子进程终止,而父进程既不终止也不调用 wait 清理子进程:


#include <unistd.h> #include <stdlib.h>int main(void) {  pid_t pid=fork();   if(pid<0) {    perror("fork");    exit(1);   }  if(pid>0) { /* parent */    while(1);   }  /* child */  return 0; }
复制代码


若调用成功则返回清理掉的子进程 id,若调用出错则返回-1。父进程调用 wait 或 waitpid 时可能会:


  • 阻塞(如果它的所有子进程都还在运行)。

  • 带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信

  • 息)。

  • 出错立即返回(如果它没有任何子进程)。

  • 这两个函数的区别是:

  • 如果父进程的所有子进程都还在运行,调用 wait 将使父进程阻塞,而调用 waitpid 时如 果在 options 参数中指定 WNOHANG 可以使父进程不阻塞而立即返回 0。

  • wait 等待第一个终止的子进程,而 waitpid 可以通过 pid 参数指定等待哪一个子进程。

  • 可见,调用 wait 和 waitpid 不仅可以获得子进程的终止信息,还可以使父进程阻塞等待子进 程终止,起到进程间同步的作用。如果参数 status 不是空指针,则子进程的终止信息通过 这个参数传出,如果只是为了同步而不关心子进程的终止信息,可以将 status 参数指定为 NULL。

  • 例 waitpid


#include <sys/types.h> #include <sys/wait.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>int main(void) {  pid_t pid;  pid = fork();   if (pid < 0) {    perror("fork failed");    exit(1);   }  if (pid == 0) {     int i;    for (i = 3; i > 0; i--) {       printf("This is the child\n");       sleep(1);    }    exit(3);   } else {    int stat_val;    waitpid(pid, &stat_val, 0);    if (WIFEXITED(stat_val))      printf("Child exited with code %d\n", WEXITSTATUS(stat_val));    else if (WIFSIGNALED(stat_val))      printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));  }  return 0;}
复制代码


wait 阻塞函数,阻塞等待子进程结束 waitpid 4 种情况 < -1 = -1 = 0 > 0


  • 进程的退出状态

  • 非阻塞标志,WNOHANG

  • 获取进程退出状态的函数见 manpages

  • 调用进程若无子进程,则 wait 出错返回

总结

本文介绍了僵尸进程和孤儿进程的概念解决方案。僵尸进程: 子进程退出,父进程没有回收子进程资源(PCB),则子进程变成僵尸进程;孤儿进程: 父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为 1 号 进程 init 进程,称为 init 进程领养孤儿进程。

发布于: 2 小时前阅读数: 6
用户头像

轻口味

关注

🏆2021年InfoQ写作平台-签约作者 🏆 2017.10.17 加入

Android、音视频、AI相关领域从业者。 邮箱:qingkouwei@gmail.com

评论

发布
暂无评论
Android C++系列:Linux进程(三)