进程等待

133 阅读1分钟

为什么要进行进程等待

子进程是有父进程创建的,而且父进程要承担一个重要的任务---回收子进程的数据资源和数据结构,如果没有父进程进行回收,当子进程结束后,它就会称为僵尸进程,就会造成资源泄露。

还有子进程运行的结果要由父进程进行获取,结果对还是不对,是否异常退出等

父进程通过进程等待的方式,回收子进程的资源,获取子进程退出信息。

wait()


#include<sys/wait.h>

pid_t wait(int*status);

这个函数如果成功等待那就返回等待进程的pid,否则返回-1

一个例子

#include<iostream>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<cstdlib>
using namespace std;
int main()
{
    pid_t id=fork();
    if(id==0)
    {
        int cnt=5;
        while(cnt--)
        {
            cout<<"子进程的id"<<getpid()<<"父进程的id"<<getppid()<<endl;
            sleep(1);
        }
        exit(0);
    }
    pid_t ret=wait(NULL);
    if(ret>0)
    cout<<"父进程等待成功"<<ret<<endl;
    
    

    
}

image.png

waitpid()

pid_ t waitpid(pid_t pid, int *status, int options);

返回值:

当正常返回的时候waitpid返回收集到的子进程的进程ID;

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

如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;

status

这里重点讲一下status参数

对于子进程要么运行成功正常终止,要么遭遇异常被信号所杀,status是一个输出型参数由操作系统所填充,如果传递空,那么意味着表示不关心子进程的退出状态信息。父进程等待子进程一个重要的作用就是要知道子进程的退出信息,status就是让父进程获取退出信息的。status是一个位图

image.png

也就是说退出码就是status右移8位再和0xff按位与得到的。

#include<iostream>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<cstdlib>
using namespace std;
int main()
{
    pid_t id=fork();
    if(id==0)
    {
        int cnt=5;
        while(cnt--)
        {
            cout<<"子进程的id"<<getpid()<<"父进程的id"<<getppid()<<endl;
            sleep(1);
        }
        exit(10);
    }
    cout<<"父进程开始等待"<<endl;
    //pid_t ret=wait(NULL);
    int status=0;
    pid_t ret=waitpid(id,&status,0);
    if(ret>0)
    {
         cout<<"父进程等待成功"<<ret<<endl;
         int exit_code=(status>>8)&0xff;
         cout<<"status exit code"<<exit_code<<endl;
    }
    else
    {
        cout<<"父进程等待失败"<<endl;
    }
   
    
    

    
}

image.png 可以看到这里的退出码正是10

options

这里还有另外一个参数这里的options实际上是进程等待方式,我前面写的代码的options是0,表示最常见的阻塞等待。阻塞等待就是单纯的等,不做其他的任何行动。 参数options提供了一些额外的选项来控制waitpid,参数 option 可以为 0 或可以用"|"运算符把它们连接起来使用,比如:

ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);

如果我们不想使用它们,也可以把options设为0,如:

ret=waitpid(-1,NULL,0);

WNOHANG 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若结束,则返回该子进程的ID。

示例

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <sys/wait.h>

int main()

{

pid_t pid;

pid = fork();

if(pid < 0){

printf("%s fork error\n",__FUNCTION__);

return 1;

}else if( pid == 0 ){ //child

printf("child is run, pid is : %d\n",getpid());

sleep(5);

exit(1);

} else{

int status = 0;

pid_t ret = 0;

do

{

ret = waitpid(-1, &status, WNOHANG);//非阻塞式等待

if( ret == 0 ){

printf("child is running\n");

}

sleep(1);

}while(ret == 0);

if( WIFEXITED(status) && ret == pid ){

printf("wait child 5s success, child return code is :%d.\n",WEXITSTATUS(status));
}else{

printf("wait child failed, return.\n");

return 1;

}

}

return 0;

}


深入理解

用户将status传入给父进程,父进程在内核当中,然后父进程获取子进程的退出码和退出信号

image.png