• Linux内核学习笔记(4)-- wait、waitpid、wait3 和 wait4


      进程调用 exit() 退出执行后,被设置为僵死状态,这时父进程可以通过 wait4() 系统调用查询子进程是否终结,之后再进行最后的操作,彻底删除进程所占用的内存资源。 wait4() 系统调用由 linux 内核实现,linux 系统通常提供了 wait()、waitpid()、wait3()、wait4() 这四个函数,四个函数的参数不同,语义也有细微的差别,但是都返回关于终止进程的状态信息。

    1、wait() 函数:

      wait() 函数的原型是:

    #include <sys/types.h>        // 提供类型 pid_t 的定义
    #include <sys/wait.h>
    
    pid_t wait(int *status);

      当进程调用 wait() 时,会暂停目前进程的执行(即阻塞),由 wait() 来自动分析是否当前进程的某个子进程已经退出,如果找到了这样一个已经变成僵尸进程的子进程,wait 就会收集这个子进程的信息,并将其彻底销毁后返回;如果没有找到这样一个子进程,wait 就会一直阻塞在这里,直到出现僵尸进程。

      参数 status 保存着子进程退出时的一些状态(包括 task_struct、thread_info及内核栈等)它是一个指向 int 类型的指针;如果不在意子进程的结束状态值,只想把这个僵尸进程消灭掉(实际上,大多数时候都是这样做的),则可以将这个参数设为 NULL,即:

    pid = wait(NULL);        // 不管子进程的结束状态,直接杀死进程

      如果 wait() 调用成功,则会返回被收集子进程的进程ID;如果被调用进程没有子进程,则调用失败,返回 -1

      接下来用一段代码来演示一下 wait() 的用法:

      1 #include <unistd.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>                                                                    
      4 #include <sys/types.h>
      5 #include <sys/wait.h>
      6 
      7 void main(){
      8     pid_t fpid,rpid;
      9     fpid = fork();
     10     if(fpid < 0){        
     11         perror("error on forking!
    ");
     12     }
     13     else if(fpid == 0){
     14         printf("this is a child process! the pid is %d
    ",getpid());
     15         sleep(3);
     16     }
     17     else{
     18         rpid = wait(NULL);          // 如果 wait()调用成功,则返回子进程的PID;如果调用失败,则返回 -1
     19         printf("Catch the child process with pid of %d
    ",rpid);
     20     }
     21     exit(0);
     22 }    

    输出结果如下:

       关于 status 参数,比较复杂,暂时不做讨论,可以参考这里:https://www.ibm.com/developerworks/cn/linux/kernel/syscall/part3/index.html

    2、waitpid() 函数:

      函数原型:

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

       waitpid() 函数的功能与 wait() 的功能类似,不过,它比 wait() 函数多了两个参数:

    1)参数 pid 为欲等待的子进程的识别码:

      pid < -1 ;等待进程组 ID 为 pid 绝对值的进程组中的任何子进程;

      pid = -1 ;等待任何子进程,此时 waitpid() 相当于 wait()。实际上,wait()就是 pid = -1、options = 0 的waitpid(), 且有:

    static inline pid_t wait(*status){
        return waitpid(-1,*status,0);  
    }

      pid = 0 ;等待进程组 ID 与当前进程相同的任何子进程(也就是等待同一个进程组中的任何子进程);

      pid > 0 ;等待任何子进程 ID 为 pid 的子进程,只要指定的子进程还没有结束,waitpid() 就会一直等下去。

    2)参数 options 提供一些额外的选项来控制 waitpid():

      WNOHANG;如果没有任何已经结束了的子进程,则马上返回,不等待;

      WUNTRACED;如果子进程进入暂停执行的情况,则马上返回,但结束状态不予理会;

      也可以将这两个选项组合起来使用,使用 OR 操作。如果不想使用这两个选项,也可以直接把 options 设为0 ,如下:

    waitpid(-1,NULL,WNOHANG | WUNTRACED);     // 没有任何已结束了的子进程或子进程进入暂停执行的状态,则马上返回不等待
    waitpid(-1,NULL,0);                // options 设为0,则 waitpid() 会一直等待,直到有进程退出

    3)waitpid() 的返回值,有三种:

    a)正常返回时,waitpid() 返回收集到的子进程的PID;

    b)如果设置了 WNOHANG,而调用 waitpid() 时,没有发现已退出的子进程可收集,则返回0;

    c)如果调用出错,则返回 -1,这时erron 会被设置为相应的值以指示错误所在。(当 pid 所指示的子进程不错在,或此进程存在,但不是调用进程的子进程, waitpid() 就会返回出错,这时 erron 被设置为 ECHILD)

      1 #include <sys/types.h> 
    2 #include <sys/wait.h> 3 #include <unistd.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 7 void main(){ 8 pid_t fpid,rpid; // fpid为fork()的返回值,rpid为waitpid()的返回值 9 fpid = fork(); 10 if(fpid < 0){ 11 printf("error on forking"); 12 } 13 else if(fpid == 0){ // 子进程中 fork() 返回值为0 14 printf("this is a child process,pid is %d ",getpid()); 15 sleep(10); // 睡眠10s,10s 后子进程退出 16 exit(0); 17 } 18 do{          // 父进程中,fork()返回新创建子进程的 PID 19 rpid = waitpid(fpid,NULL,WNOHANG); // 等待 PID = fpid 的进程(即子进程)退出,设置了WNOHANG选项,表明当没有发现已退出的子进程时不用等待直接返回,返回值为0; 20 if(rpid == 0){ // rpid = 0,说明没有发现已退出的子进程 21 printf("No child exited "); 22 sleep(1); 23 } 24 }while(rpid == 0); 25 if(fpid == rpid) // 成功收集了退出的子进程,返回值为被收集子进程的PID 26 printf("successfully get child process %d ",rpid); 27 else 28 printf("error! "); 29 }

    结果如下:

      从结果中可以看到,在子进程休眠的10s时间里,waitpid() 并没有一直等待,而是直接返回0,然后做自己的事情(睡眠1s),如此重复了10次;当子进程退出时,waitpid() 收集到退出的子进程,并返回所收集子进程的PID。

     3、wait3()、wait4() 函数:

      函数原型:

    #include <sys/tpyes.h>
    #include <sys/wait.h>
    
    pid_t wait3(int *status,int options,struct rusage *rusage);
    pid_t wait4(pid_t pid,int *status,int options,struct rusage *rusage);

       wait3() 和 wait4() 函数除了可以获得子进程状态信息外,还可以获得子进程的资源使用信息,这些信息是通过参数 rusage 得到的。而 wait3() 与 wait4() 之间的区别是,wait3() 等待所有进程,而 wait4() 可以根据 pid 的值选择要等待的子进程,参数 pid 的意义与 waitpid() 函数的一样。

     本文主要参考:

    https://www.ibm.com/developerworks/cn/linux/kernel/syscall/part3/index.html

     

  • 相关阅读:
    C#网络编程(异步传输字符串)
    C#网络编程(同步传输字符串)
    C#网络编程(基本概念和操作)
    Asp.Net 构架(HttpModule 介绍)
    Asp.Net 构架(Http Handler 介绍)
    Asp.Net构架(Http请求处理流程)
    XML的应用 ---- 从一个范例看xml数据、xsd验证、xslt样式
    jQuery的ajax跨域实现
    常见26个jquery使用技巧详解
    常用Request对象获取请求信息
  • 原文地址:https://www.cnblogs.com/tongye/p/9558320.html
Copyright © 2020-2023  润新知