• 2.5 进程控制之wait函数


    一、绪论

    一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果

    是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用waitwaitpi

    d获取这些信息,然后彻底清除掉这个进程。

    二、wait()

    1. 功能:父进程调用wait函数可以回收子进程终止信息。该函数有三个功能:

    ① 阻塞等待子进程退出

    ② 回收子进程残留资源

    ③ 获取子进程结束状态(退出原因)

    wait一旦被调用,就会一直阻塞在这里,直到有一个子进程退出出现为止。

    2. 函数原型:

    pid_t wait(int *status); 

    成功:清理掉的子进程ID;失败:-1 (没有子进程)

    使用wait函数传出参数status来保存进程的退出状态 (正常终止→退出值;异常终止→终止信号)。借助宏函数来进一步判断进程终止的具体原因。

    宏函数可分为如下三组:

    1). WIFEXITED(status) 为非0 → 进程正常结束

        WEXITSTATUS(status) 如上宏为真,使用此宏 → 获取进程退出状态 (exit的参数)

    2). WIFSIGNALED(status) 为非0 → 进程异常终止

        WTERMSIG(status) 如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。

    *3). WIFSTOPPED(status) 为非0 → 进程处于暂停状态

        WSTOPSIG(status) 如上宏为真,使用此宏 → 取得使进程暂停的那个信号的编号。

        WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行

    3. 例程

     1 #include <unistd.h>
     2 #include <stdlib.h>
     3 #include <stdio.h>
     4 #include <sys/wait.h>
     5 
     6 int main(void)
     7 {
     8     pid_t pid, wpid;
     9     int status; //定义传出参数
    10 
    11     pid = fork();
    12     if(pid == -1){
    13         perror("fork error");
    14         exit(1);
    15     } else if(pid == 0){    //子进程
    16         printf("I'm process child, pid = %d
    ", getpid());
    17 #if 0
    18         execl("./abnor", "abnor", NULL);
    19         perror("execl error");
    20         exit(1);
    21 #endif
    22         sleep(1);                
    23         exit(20);
    24     } else {
    25         //wpid = wait(NULL);     //无传出参数,无需判断
    26         wpid = wait(&status);    //status为传出参数,wpid返回的进程ID
    27         if(WIFEXITED(status)){    //正常退出 非0
    28             printf("I'm parent, The child process%d exit normally
    ", wpid);
    30             printf("return value:%d
    ", WEXITSTATUS(status));//获取退出值31 
    32         } else if (WIFSIGNALED(status)) {    //异常退出
    33             printf("The child process exit abnormally, killed by signal %d
    ", WTERMSIG(status));//获取终止信号编号                                   
    36         } else {
    37             printf("other...
    ");
    38         }
    39     }
    40     return 0;
    41 }

    编译与执行结果:

    异常退出:

    二、waitpid()

    1. 功能与wait相同,但可指定pid进程清理,可以不阻塞。

    pid_t waitpid(pid_t pid, int *status, in options);

    成功:返回清理掉的子进程ID;失败:
    -1(无子进程)

    特殊参数和返回情况,参数pid

      > 0 回收指定ID的子进程

      -1 回收任意子进程(相当于wait

      0 回收和当前调用waitpid一个组的所有子进程

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

    注意:

      1)参3WNOHANG(非阻塞),且子进程正在运行,则返回0。

      2)一次waitwaitpid调用只能清理一个子进程,清理多个子进程应使用循环

    2. 例程一

     1 #include <sys/types.h>
     2 #include <sys/wait.h>
     3 #include <unistd.h>
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 int main(void)
     7 {
     8     pid_t pid;
     9     int i;
    10     int stat_val;
    11 
    12     pid = fork();
    13 
    14     if (pid < 0) {
    15         perror("fork failed");
    16         exit(1);
    17     }
    18     if (pid == 0) {
    19         for (i = 3; i > 0; i--) {
    20             printf("This is the child
    ");
    21             sleep(1);
    22         }
    23         exit(34);
    24     } else {
    25         waitpid(pid, &stat_val, 0);     //0阻塞
    26         if (WIFEXITED(stat_val))  ////stat_val为传出参数
    27             printf("Child exited with code %d
    ", WEXITSTATUS(stat_val));
    28         else if (WIFSIGNALED(stat_val))
    29             printf("Child terminated abnormally, signal %d
    ", WTERMSIG(stat_val));
    30     }
    31     return 0;
    32 }

    编译与执行结果:

    例程二(循环清理多个子进程)

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <stdlib.h>
     4 #include <sys/wait.h>
     5 
     6 int main(int argc, char *argv[])
     7 {
     8     int n = 5, i;                
     9     pid_t p;
    10 
    11     for(i = 0; i < n; i++)     {
    12            p = fork();
    13        if(p == 0) break;            
    14        }
    15     if(n == i){  // parent
    16         sleep(n);
    17         printf("I am parent, pid = %d
    ", getpid());
    18             for (i = 0; i < n; i++) {
    19                 p = waitpid(0, NULL, WNOHANG);
    20                 printf("wait  pid = %d
    ", p);
    21                }
    22     } else {
    23         sleep(i);
    24         printf("I'm %dth child, pid = %d
    ", i+1, getpid());
    25     }
    26     return 0;
    27 }

    编译与执行结果:

  • 相关阅读:
    Parse Notification for IOS
    微信回调:Activity 调用 finish()之后,该acitivity的实例并不为空
    Android Studio 使用微博SDK Demo的问题总结
    Android Activity切换动画
    分享那些坑
    TextColor java 代码
    奇怪的Bug: 点击事件穿透应用,激活桌面的另一个应用
    FragmentStatePagerAdapter VS FragmentPagerAdatper
    android:fillViewport="true"
    用两种方式获取Bitmap的不同结果
  • 原文地址:https://www.cnblogs.com/lxl-lennie/p/10231742.html
Copyright © 2020-2023  润新知