父进程对于子进程等待的四种解决方式

目录

一、阻塞等待

二、循环式非阻塞等待

三、父进程忽略SIG_CHLD信号

四、双fork策略


父进程需要通过等待,回收子进程资源,获取子进程退出信息,否则子进程会成为僵尸进程。

一、阻塞等待

使用wait函数或者waitpid函数(option参数传0)实现阻塞等待

弊端:如果子进程一直不退出,父进程将一直处于阻塞状态

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void ChildRun()
{
    int i=0;
    for(i=0;i<5;++i)
    {
        printf("Child process is running!\n");
    }
}
int main()
{
    pid_t id=fork();
    //子进程
    if(id==0)
    {                                                                             
        ChildRun();                                 
        exit(0);//子进程退出      
    }              
    //父进程                                   
    int status=0;                   
    pid_t rid=wait(&status);
    if(rid>0)                           
    {                  
        printf("Father process wait success! status:%d, child quit code:%d, child quit signal:%d\n",status,(status>>8)&0xFF,status&0x7F);
    }                                                              
    else                                                    
    {                                                     
        printf("Father process wait fialed!\n");                                                                                                                                       
    }                                                  
    return 0;                                  
}

二、循环式非阻塞等待

使用waitpid函数(option参数传WNOHANG)

弊端:资源消耗大,能效低

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
 
void ChildRun()
{
    int i=0;
    for(i=0;i<5;++i)
    {
        printf("Child process is running!\n");
    }
}
 
void DoOtherthing()
{
    printf("Child process is not end! Father process is do other thing...\n");
}
int main()
{
    pid_t id = fork();
    if (id < 0)
    {
        printf("fork error!\n"); // 子进程创建失败
    }
    else if (id == 0) // 子进程执行
    {
        ChildRun();
        exit(123);
    }
    else // 父进程执行
    {
        int status = 0;
        pid_t rid = waitpid(id, &status, WNOHANG); // 非阻塞等待
        // 子进程未终止
        while (rid == 0)
        {
            DoOtherthing(); // 父进程做其他事情
            rid = waitpid(id, &status, WNOHANG);
        }
        
        // 子进程等待失败
        if (rid == -1)
        {
            printf("wait failed!\n");
        }
        else // 子进程等待成功
        {
            if (WIFEXITED(status)) // 子进程正常终止
            {
                printf("wait success! child exit code:%d\n", WEXITSTATUS(status));
            }
            else // 子进程异常终止
            {
                printf("wait success! child abnormal exit\n");
            }
        }
    }
    return 0;
}

三、父进程忽略SIG_CHLD信号

子进程退出时会给父进程发送17号信号:SIG_CHLD,父进程调用signal函数忽略该信号,则子进程结束后会自动释放资源,无需父进程等待

#include <iostream>
#include <signal.h>
#include <sys/wait.h>
using namespace std;
void DoOtherThing()
{
    cout << "do other things" << endl;
}
int main()
{
    signal(SIGCHLD, SIG_IGN); // 忽略SIGCHLD信号
    for (int i = 0; i < 5; ++i)//创建5个子进程
    {
        pid_t id = fork(); // 创建子进程
        if (id == 0)       // 子进程
        {
            cout << "I am child process, pid is: " << getpid() << endl;
            sleep(1);
            exit(1);
        }
    }
    // 父进程
    while (true)
    {
        DoOtherThing();
        sleep(1);
    }
}

四、双fork策略

父进程采用阻塞等待的方式等待子进程,但是为了避免子进程不退出而导致父进程一直阻塞的问题,所以产生了双fork策略:

子进程额外创建孙子进程,让孙子进程代替子进程完成相关任务,同时子进程立即退出,父进程等待子进程成功。由于子进程的退出,孙子进程成为了孤儿进程,孤儿进程结束后会被操作系统领养,进而释放资源,无需被等待。

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

int main() {
    pid_t pid_b, pid_c;
    int status;

    // 父进程创建子进程B
    pid_b = fork();
    if (pid_b < 0) {
        // fork失败
        perror("fork failed");
        exit(EXIT_FAILURE);
    } else if (pid_b == 0) {
        // 子进程B的代码
        printf("This is child process B (PID: %d)\n", getpid());

        // 子进程B创建孙子进程C
        pid_c = fork();
        if (pid_c < 0) {
            // fork失败
            perror("fork failed in child process B");
            exit(EXIT_FAILURE);
        } else if (pid_c == 0) {
            // 孙子进程C的代码
            printf("This is grandchild process C (PID: %d)\n", getpid());

            // 孙子进程C执行其任务...
            // 这里只是简单地睡眠一段时间来模拟任务执行
            sleep(10);

            // 孙子进程C任务完成,退出
            printf("Grandchild process C exiting...\n");
            exit(EXIT_SUCCESS);
        } else {
            // 子进程B中,孙子进程C已经创建并运行
            // 子进程B现在可以安全地退出
            printf("Child process B exiting after creating grandchild process C (PID: %d)\n", pid_c);
            exit(EXIT_SUCCESS);
        }
    } else {
        // 父进程的代码
        printf("This is parent process (PID: %d)\n", getpid());

        // 父进程等待子进程B的退出
        printf("Parent process waiting for child process B (PID: %d) to exit...\n", pid_b);
        waitpid(pid_b, &status, 0); // 使用waitpid等待特定的子进程B
        if (WIFEXITED(status)) {
            printf("Child process B exited with status %d\n", WEXITSTATUS(status));
        } else {
            printf("Child process B did not exit normally\n");
        }

        // 父进程可以选择继续执行其他任务
        // 或者简单地结束
        printf("Parent process exiting...\n");
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南林yan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值