C语言wait函数和fork使用

2024-07-08  本文已影响0人  Feel_狗焕

目录:
1、wait函数和waitpid函数
1.1、wait和waitpid出现的原因
1.2、wait()和waitpid()函数使用
1.3、wait获取staus后检测处理
2、使用示例
2.1、wait()使用
2.2、waitpid使用


1、wait函数和waitpid函数:

1.1、wait和waitpid出现的原因:

1)、SIGCHLD:

1.2、wait()和waitpid()函数使用:

wait函数在默认的如下系统库:

#include <sys/types.h>   
#include <sys/wait.h>
pid_t wait(int *status)

进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就 会一直阻塞在这里,直到有一个出现为止。waitpid()的作用和wait()一样,但它并不一定要等待一个终止的子进程,它还有若干选项,如可提供一个非阻塞版本的wait()功能,也能支持作用控制。
参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就象下面这样:

pid = wait(NULL); 

1)、wait()函数:

函数签名: pid_t wait(int *status);
函数传入值:这里的status是一个整型指针,是该子进程退出的状态。若status不为空,则通过它可以获取子进程的结束状态。另外,子进程的结束状态有Linux系统中特定的宏来检测实际的进程返回的值;
函数返回值:成功返回已结束运行的子进程id,失败直接返回-1;

2)、waitpid()函数:

2.1)、函数签名:pid_t waitpid(pid_t pid, int *status, int options);
2.2)、函数入参:

pid:

options:
提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用,比如:
ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);
如果我们不想使用它们,也可以把options设为0,如:
ret=waitpid(-1,NULL,0);

2.3)、函数返回值:

1.正常结束返回子进程的id;
2.使用WNOHANG且没有子进程退出返回0;
3.失败返回-1;

1.3、wait获取staus后检测处理:

由于在使用waitpid()函数的时候获取到的进程状态值对其直接输出会与实际返回值不一致,所以需要引用(WIFEXITED|WEXITSTATUS)等宏定义来输出进程实际的状态信息值,宏定义和对应的描述,如下:

1)、WIFEXITED(status): 如果进程子进程正常结束,返回一个非零值;

2)、WIFSIGNALED(status): 子进程因为捕获信号而终止,返回非零值;

3)、WIFSTOPPED(status): 如果进程被暂停,返回一个非零值;


2、使用示例:

2.1、wait()使用:

fork是一个创建新进程的系统调用。当调用 fork 时,它会创建一个与调用进程几乎完全相同的新进程(子进程)。fork 返回两次,一次在父进程中,另一次在子进程中。具体来说,fork 在父进程和子进程中的行为如下:
父进程:调用 fork 后,fork 返回子进程的 PID(正整数)。
子进程:调用 fork 后,fork 返回 0。
因此,fork 可以通过返回值来区分它是在父进程中还是在子进程中运行。

下面的代码流程如下:
1.父进程执行fork()创建一个子进程,fork()返回创建子进程的PID值非0值,进入else判断即父进程执行代码区域调用wait()方法等待子进程结束;
2.同样的代码拷贝到创建的子进程中,在子进程第一次调用fork()时候返回0值然后进去执行子进程执行代码相关逻辑(要是在子进程执行代码区域再次执行fork()那么子进程就会在创建出孙子进程);

void forkUsed(void){
    int pid;
    printf("father progress\n");
    if (0 ==fork()){
        // 子进程执行代码
        printf("father progress forked\n");

    }else{
        // 父进程执行代码
        if (-1 ==(pid=wait(NULL))){
            printf("no child progress,and wait() return -1\n");
        } else{
            printf("wait() return child progress pid:%d\n",pid);
        }
    }

    /*
     * 输出结果为:
     * father progress
     * father progress forked
     * wait() return child progress pid:xxx
     */
}

2.2、waitpid()使用:

#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>

int main(){
    pid_t pc,pr;
    pc= fork();
    if (pc == 0){
        sleep(5);
        exit(0);
    }else{
        // 循环测试子进程是否退出
        do {
            pr= waitpid(pc,NULL,WNOHANG);
            //若子进程还未退出,则父进程暂停1s
            if (pr ==0){
                printf("The child process has not exited\n");
                sleep(1);
            }
        } while (pr ==0);

        if (pr == pc){
            printf("get child exit code:%d\n",pr);
        } else{
            printf("waitpid error\n");
        }
    }

    /*
     * 输出结果:
     * The child process has not exited
     * The child process has not exited
     * The child process has not exited
     * The child process has not exited
     * The child process has not exited
     * get child exit code:xxx
     * 
     * 子进程暂停5s,而在父进程每隔1s来判断该子进程是否退出,所以这里总共打印5条。
     * 说明waitpid没有阻塞,且指定子进程没有退出返回0,指定进程退出返回其进程ID
     */
}
上一篇下一篇

猜你喜欢

热点阅读