C语言 父进程退出确保子进程也终止

C 和类 Unix 系统中,当父进程退出时,子进程通常会变成孤儿进程,并被 init 或 systemd(在现代 Linux 系统中)收养。孤儿进程会继续运行,直到它们完成或被显式终止。如希望子进程在父进程退出后自动结束,可能需要采取额外的措施。

1、使用 prctl 设置 Pdeathsig(Linux-specific)

在 Linux 上,可以使用 prctl() 系统调用设置 Pdeathsig,指定父进程退出时子进程应该接收到的信号。通常,可以发送 SIGKILLSIGTERM 来终止子进程。

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

int main() {
    pid_t pid = fork();
    if (pid == 0) {  // 子进程
        // 设置父进程退出时向子进程发送 SIGTERM 信号
        prctl(PR_SET_PDEATHSIG, SIGTERM);

        // 子进程模拟工作
        while (1) {
            printf("Child is running...\n");
            sleep(1);
        }
    } else if (pid > 0) {  // 父进程
        // 父进程模拟工作
        printf("Parent is running...\n");
        sleep(5);  // 父进程工作一段时间
        printf("Parent exiting...\n");
    } else {
        perror("fork failed");
    }
    return 0;
}

2、使用 setsid() 创建新的会话(Linux/Unix)

另一种方法是使用 setsid() 创建一个新的会话和进程组,这样子进程就不再是父进程的直接子进程,从而避免成为孤儿进程。然而,这种方法不能保证子进程在父进程退出时被杀死。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    pid_t pid = fork();
    if (pid == 0) {  // 子进程
        setsid();  // 创建一个新的会话,子进程不再是父进程的直接子进程
        while (1) {
            printf("Child is running...\n");
            sleep(1);
        }
    } else if (pid > 0) {  // 父进程
        printf("Parent is running...\n");
        sleep(5);  // 父进程工作一段时间
        printf("Parent exiting...\n");
    } else {
        perror("fork failed");
    }
    return 0;
}

3、父进程管理子进程的生命周期

另一种方法是由父进程显式管理子进程的生命周期。在父进程退出之前,确保通过 waitpid() 或类似的函数等待并终止子进程。

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

int main() {
    pid_t pid = fork();
    if (pid == 0) {  // 子进程
        while (1) {
            printf("Child is running...\n");
            sleep(1);
        }
    } else if (pid > 0) {  // 父进程
        printf("Parent is running...\n");
        sleep(5);  // 父进程工作一段时间
        printf("Parent exiting...\n");
        waitpid(pid, NULL, 0);  // 父进程等待子进程结束
    } else {
        perror("fork failed");
    }
    return 0;
}

推荐阅读
cjavapy编程之路首页