zoukankan      html  css  js  c++  java
  • linux多进/线程编程(3)——wait、waitpid函数和孤儿、僵尸进程

    当使用fork创建多个进程后,需要解决子进程回收的问题。waitwaitpid函数就是做这个工作的。

    假设子进程没有合理的回收,可能会带来两个问题:

    1.孤儿进程(父进程挂了,子进程活着),孤儿进程会被init进程回收,可以理解其没有危害,不会占用资源。

    2.僵尸进程(子进程挂了,父进程活着),僵尸进程是当父进程活着时,子进程没有其他进程帮忙回收后产生的“有害进程”,所以僵尸必须要回收,否则僵尸进程太多了会占用系统资源。此时就需要用到wait或waitpid函数。

    wait和waitpid的区别在于:

    wait函数是阻塞的,必须等到子进程被回收才会执行wait之后的代码;

    waitpid可以设置为非阻塞的,不过非阻塞可能带来新的问题,子进程还没有回收waitpid这句代码就走完了(一般会写循环,通过判断返回值解决)。

    wait:

    WAIT(2)                                                                                Linux Programmer's Manual                                                                               WAIT(2)
    
    NAME
           wait, waitpid, waitid - wait for process to change state
    
    SYNOPSIS
           #include <sys/types.h>
           #include <sys/wait.h>
    
           pid_t wait(int *status);
    
           pid_t waitpid(pid_t pid, int *status, int options);

    返回值:

    RETURN VALUE
           wait(): on success, returns the process ID of the terminated child; on error, -1 is returned.
    
           waitpid(): on success, returns the process ID of the child whose state has changed; if WNOHANG was specified and one or more child(ren) specified by pid exist, but have not yet changed state,
           then 0 is returned.  On error, -1 is returned.

    waitpid的参数:

    The child state changes to wait for are specified by ORing one or more of the following flags in options:
    
           WEXITED     Wait for children that have terminated.
    
           WSTOPPED    Wait for children that have been stopped by delivery of a signal.
    
           WCONTINUED  Wait for (previously stopped) children that have been resumed by delivery of SIGCONT.
    
           The following flags may additionally be ORed in options:
    
           WNOHANG     As for waitpid().
    
           WNOWAIT     Leave the child in a waitable state; a later wait call can be used to again retrieve the child status information.

    wait用法示例:

    pid_t pid = fork();
    
      if (pid == 0) {
    
        //while (true) {
          //sleep(1);
        //}
        printf("i am child, i will die
    ");
        sleep(2);
        //return 101;
        exit(2);
      } else if (pid > 0) {
        printf("i am parent, wait for a child die
    ");
        int status { 0 };
    
        pid_t wait_pid = wait(&status);//1,阻塞等待(子进程死亡);2,回收子进程资源(避免僵尸进程);3,查看状态(死亡原因)
        printf("wait ok, wait_pid=%d, pid=%d
    ", wait_pid, pid);
    
        if (WIFEXITED(status)) {
          printf("child exit with %d
    ", WEXITSTATUS(status));
        }
    
        if (WIFSIGNALED(status)) {
          printf("child killed by %d
    ", WTERMSIG(status));
        }
    
    
        while (true) {
          sleep(1);
        }
      }

    waitpid用法示例:

    pid_t pid = fork();
      int ret { 0 };
    
      if (pid == 0) {
        printf("i am child, pid=%d
    ", getpid());
        sleep(2);
    
        exit(101);
      } else if (pid > 0) {
        printf("i am parent, self=%d, child_pid=%d
    ", getpid(), pid);
    
        //不阻塞可能会带来一个问题,子进程还没回收,这句代码就走完了,所以要加循环(让代码阻塞在这里。。这。。。那还不如直接用wait????)
        //WNOHANG: 不阻塞
        int status { 0 };
    
        while ((ret = waitpid(-1, &status, WNOHANG)) == 0) {
          sleep(1);
        }
        printf("ret=%d
    ", ret);
    
        if (WIFEXITED(status)) {
          printf("child exit with %d
    ", WEXITSTATUS(status));
        }
    
        if (WIFSIGNALED(status)) {
          printf("child killed by %d
    ", WTERMSIG(status));
        }
    
        ret = waitpid(-1, nullptr, WNOHANG);
    
        if (ret < 0) {
          perror("wait err");
        }
    
        while (true) {
          sleep(1);
        }
      }

    waitpid回收多个子进程(且忽略子进程状态即死亡原因)

      int i { 0 };
      int n { 5 };
      int ret { 0 };
      pid_t pid { 0 };
    
      for (i = 0; i < n; ++i) {
        pid = fork();
        if (pid == 0) {
          printf("i am child, pid=%d
    ", getpid());
    
          sleep(2);
          break;
        }
      }
    
      if (pid > 0) {
    
        while ((ret = waitpid(-1, nullptr, WNOHANG)) != -1) {
          sleep(1);
          printf("ret = %d
    ", ret);
        }
    
        printf("ret = %d
    ", ret);
    
        while (true) {
          sleep(1);
          printf("i am parent, self=%d, child_pid=%d
    ", getpid(), pid);
        }
      }
  • 相关阅读:
    .net core 大型事务的处理办法
    .net Core把一个list集合里面的所有字段的数值汇总
    C#使用模板导出Excel
    JQuery滚动分页查询功能
    返回一个条件表达式树的拓展方法
    C++类的大小
    基数排序-八大排序汇总(8)
    归并排序-八大排序汇总(7)
    快速排序(交换排序)-八大排序汇总(6)
    希尔排序(插入排序)-八大排序汇总(5)
  • 原文地址:https://www.cnblogs.com/kongweisi/p/14623277.html
Copyright © 2011-2022 走看看