linux进程中的wait()和waitpid()

前言:wait() 和 waitpid() 函数在C语言中有释放子进程遗留资源的作用。当一个子进程结束时调用exit()或_exit(),会进入僵死状态,它的资源(如内存、打开的文件描述符等)并不会立即被系统回收。这些资源会保留,直到父进程调用 wait() 或 waitpid() 来收集子进程的状态信息。在父进程中调用wait()和waitpid(),会等待子进程结束,期间父进程会进入阻塞状态,直到接收到子进程结束的信号,才会继续执行。如果有多个子进程,那使用一个wait(NULL),父进程只会等待其中的一个。可以多次调用来等待所有的子进程都就结束。

一、wait()

函数头文件           #include <sys/types.h>
                                #include <sys/wait.h>
函数原型  :      pid_t wait(int *wstatus);
函数功能 :       让函数调用者进程进入到睡眠状态,等待子进程进入僵死状态后,释放相关资源并返回
函数参数:        wstatus:保存子进程退出状态值变量的指针(*****获取具体值需要使用宏定义*****)
函数返回值        wait(): 如果成功,返回终止子进程的进程ID;如果出错,则返回-1

实际上是有4种返回值,还有返回0和返回<-1,但这些都代表特定的情况,并不常见。

对于传入的参数wstatus,一些宏可以对参数进行操作:

  • WEXITSTATUS(status): 如果子进程是正常退出的,这个宏可以用来获取子进程的退出状态码。
  • WTERMSIG(status): 如果子进程是因为信号而终止的,这个宏可以用来获取导致子进程终止的信号。
  • WSTOPSIG(status): 如果子进程是被停止的,这个宏可以用来获取导致子进程停止的信号。
  • WIFEXITED(status): 检查子进程是否正常退出。如果返回非零值,表示子进程是正常退出的。
  • WIFSIGNALED(status): 检查子进程是否因接收到信号而终止。如果返回非零值,表示子进程是因为信号而终止的。
  • WIFSTOPPED(status): 检查子进程是否被停止(比如通过 SIGSTOP 信号)。如果返回非零值,表示子进程当前是停止状态

在linux多进程中,进程之间是可以发送信号的,我们可以使用这些宏来获取信号和退出的信息,得到一个布尔值,非零为真,零为假,也可以将值打印出来。

如果不关心它的信息,那参数就传一个NULL,wait(NULL)等待子进程结束。

二.waitpid()

函数头文件              #include <sys/types.h>
                                #include <sys/wait.h>
函数原型                  pid_t waitpid(pid_t pid, int *wstatus, int options);
函数参数                  pid:进程id
                                -1 可以等待任意子进程
                                >0 等待id为pid 的进程
wstatus: 保存子进程退出状态值的指针
options:选项             WNOHANG 非阻塞选项
                                 0 阻塞式与wait等同
函数返回值               成功 :>0 退出进程的pid
                                             =0 在非阻塞模式下,没有进程退出
                                 失败: -1,并设置errno

waitpid是可以选择在等待子进程结束是可以选择阻塞或非阻塞,并且是可以指定等待进程号为pid的子进程;还需要说的是调用wait(&wstatus)相当于:Waitpid (-1, &wstatus, 0),两者的实现的功能相同。

二、使用步骤

1.wait()

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main()
{
     pid_t pid1 = fork();    //创建一个pid1子进程;
     if(pid1 == -1){
         perror("fork:");
         exit(EXIT_FAILURE);
     }else if(pid1 == 0){    //pid1的代码部分;
         printf("child one\n");
         sleep(2);
         printf("child one end\n");
         exit(EXIT_SUCCESS);
     }else{                    //主进程代码部分;
         printf("parent\n");
         pid_t pid2 = fork();    //再创建一个pid2子进程;
         if(pid2 == -1){
             perror("pid2:\n");
             exit(EXIT_FAILURE);
         }else if(pid2 == 0){    //pid2的代码部分;
             printf("child twe\n");
             sleep(6);
             printf("child twe end\n");
             exit(EXIT_SUCCESS);
         }else{
             wait(NULL);//主进程代码部分;                                                                                                                                                                                                                    
             wait(NULL);//调用了wait()函数两次,所以等待两个子进程都结束后主进程才会继续执行;
             printf("parent end\n");
         }
     }
     return 0;
  }

 

可以看到主进程最先开始,然后再是子进程,即便子进程中已经sleep(),但主进程还是等待子进程结束后,才会结束。 

        注意:要熟悉这种创建的格式,有上面的主进程部分也可以一块写在下面。这样创建是规范的,因为fork()函数是有多个返回值的,在子进程中返回0,在主进程中返回它的pid,创建失败返回-1,所以使用了if else这样的格式,可以将主进程与子进程分开,不重叠。

        如果不这样去写,那么fork()创建子进程后剩下的代码子进程的会执行一次,主进程也会执行一次。

2.waitpid()

        第一个参数是给要等待的子进程的pid,-1则代表任意一个子进程,第二个参数这取决于你是否需要它子进程结束的信息,如果不需要就写NULL,第三个就是选择阻塞或非阻塞。

        在阻塞模式下,与wait()的用法差不多,waitpid (-1, &wstatus, 0)或waitpid (-1, NULL, 0),                

        在非阻塞模式下,如果waitpid(-1,&wstatus,WNOHANG)这条语句执行时,子进程还未结束,那么主进程不会阻塞,可以继续执行下面的代码,当然如果你还需要等待子进程,可以将它加入到循环中,这样既可以等待子进程,又可以在等待的时间中去执行别的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值