让进程等待--waitpid()函数

有些时候,进程之间需要协助才能完成一些任务,比如说,进程A和进程B共同完成一项任务,但是必须进程A先完成,然后进程B再开始,等进程B也完成了,任务也就完成了。
先给出一个有问题的实例,然后我们来分析并解决它:
aa.c

//父进程
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
int main(){

        pid_t pid = fork();
        if(pid == -1){
                fprintf(stderr,"%s:%s\n","Can't fork process",strerror(errno));
                exit(1);
        }

        if(!pid){
        execl("bb","bb",NULL);
        }
        FILE *my_file = fopen("test.log","r");
        char c[80];
        fscanf(my_file,"%79[^\n]\n",c);
        printf("%s\n",c);
        return 0;
}

bb.c

    //子进程
    #include <stdio.h>
    #include <unistd.h>
    int main(){
            FILE *my_file = fopen("test.log","w");
            if(my_file == NULL){
                    fprintf(stderr,"error!!!!");
            }
    
            sleep(5);
            fprintf(my_file,"Hello world!Good morning!");
            fclose(my_file);
            return 0;
    }

编译运行:

~/Desktop/MyC$ touch test.log
~/Desktop/MyC$ gcc aa.c -o aa
~/Desktop/MyC$ gcc bb.c -o bb
~/Desktop/MyC$ ./aa
|
~/Desktop/MyC$ tail -f test.log
Hello world!Good morning!

原因分析:
首先说说这个程序要达到的目的,首先父进程aa打开子进程bb,子进程负责把“Hello world!Good morning!”写入文件test.log。然后父进程aa再把test.log内容读出来。但是这个有问题的实例,在运行后,并没有打印任何内容。使用tail命令查看test.log文件时,发现数据已成功写入。

为什么会这样呢?
其实是因为创建的子进程与父进程之间已没有任何关系了。也就是说父进程并没有等待子进程执行完,就自己执行完了。有没有办法让父进程等待子进程执行完毕再继续执行呢?答案是有的,使用waitpid()函数。

waitpid()函数会等待子进程结束以后才返回。因此我们调整一下主程序aa.c的代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
int main(){

        pid_t pid = fork();
        if(pid == -1){
                fprintf(stderr,"%s:%s\n","Can't fork process",strerror(errno));
                exit(1);
        }

        if(!pid){
        execl("bb","bb",NULL);
        }
        int pid_status;
        if(waitpid(pid,&pid_status,0) == -1){
                fprintf(stderr,"error !!!");
                return 2;
        }
        FILE *my_file = fopen("test.log","r");
        char c[80];
        fscanf(my_file,"%79[^\n]\n",c);
        printf("%s\n",c);
        return 0;
}

我们在主程序中添加了

     if(waitpid(pid,&pid_status,0) == -1){
            fprintf(stderr,"error !!!");
            return 2;
    }

这段代码的意思就是要等待子程序执行完毕。

编译运行一下:

~/Desktop/MyC$ gcc aa.c -o aa
~/Desktop/MyC$ ./aa
Hello world!Good morning!

结果符合我们的预期。
分析一下waitpid(pid,pid_status,options)函数:
pid:父进程克隆子进程时会得到子进程的ID。更多进程信息尽在进程与系统调用——fork、exec
pid_status: 用来保存进程的退出信息。因为waitpid()需要修改pid_status,因此它必须是个指针。
options:可以通过man waitpid查看它的选项,如果把选项设为0,函数将等待进程结束。

什么是pid_status?
waitpid()函数结束等待时会在pid_status中保存一个值,它告诉你进程的完成情况。为了得到子进程的退出状态,可以把pid_status的值传给WEXITSTATUS()宏:

if(WEXITSTATUS(pid_status)){ //如果退出状态不是0
	puts("Error status non-zero");
}

谢谢阅读!

猜你喜欢

转载自blog.csdn.net/weixin_40763897/article/details/87612900
今日推荐