理解 Linux 中的 SIGCHLD 信号

什么是 SIGCHLD?

SIGCHLD是 Linux 和类 Unix 操作系统中的一个信号,用于通知父进程其子进程的状态发生了变化(如子进程终止、停止或继续执行)。SIGCHLD 是进程间通信的重要机制,尤其是在父进程需要管理多个子进程时。

  • SIGCHLD 的基本信息:
  • 信号编号:17
  • 默认行为:忽略(SIG_IGN)
  • 触发条件: 子进程终止(正常退出或被信号终止),子进程被信号暂停(如 SIGSTOP),子进程从暂停状态恢复(如 SIGCONT)

SIGCHLD作用

  • 通知父进程:当子进程的状态发生变化时,内核会向父进程发送 SIGCHLD 信号。
  • 避免僵尸进程:父进程可以通过捕获 SIGCHLD 信号并调用 wait() 或 waitpid()
    来回收子进程的资源,避免僵尸进程的产生。

如何处理 SIGCHLD 信号

  • 忽略 SIGCHLD 信号:可以使用 signal(SIGCHLD, SIG_IGN),从而自动回收子进程资源,不会造成僵尸进程。
  • 捕获 SIGCHLD 信号:使用 signal() 或 sigaction() 设置信号处理函数,在信号处理函数中调用 wait() 或 waitpid() 回收子进程资源。

相较于之前的父进程主动去等待子进程结束更为灵活,当子进程退出的时候内核会主动向父进程发送SIGCHLD信号,这样父进程只需要捕捉这个信号并在信号的自定义处理函数中去处理回收子进程就可以了,之前可以一直做自己的事情。

以下是一个实例代码,首先使用fork()创建了5个子进程,并退出,当进程收到SIGCHLD信号转而去执行handler函数,其中使用waitpid(-1, &status, WNOHANG),非阻塞等待任意一个进程退出,如果这里是阻塞等待那么就可能无法返回main函数(如果有子进程一直未退出),因为当用signal捕捉一个信号并进入自定义处理函数时,必须要等待自定义函数处理完毕才能继续返回main函数执行,所有程序可能会卡在waitpid,因此要使用非阻塞等待,当前没有程序退出时会返回到main函数

#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
void otherthing()
{
    std::cout << "父进程在干自己的事情" << std::endl;
}
void handler(int n)
{
    int status;//获取退出状态
    pid_t pid;
    while (1)
    {
        pid = waitpid(-1, &status, WNOHANG);//非阻塞等待任意一个进程退出
        if (pid > 0)
        {
            std::cout << "Children " << pid << "exit with " << WEXITSTATUS(status) << std::endl;
        }
        else if (pid < 0) // 目前无子进程退出
        {
            std::cout << "wait success done" << std::endl;
            break;
        }
    }
}
int main()
{
    signal(SIGCHLD, handler);
    for (int i = 0; i < 5; i++)
    {
        pid_t pid = fork();
        if (pid < 0)
        {
            std::cout << "fork fail" << std::endl;
            exit(1);
        }
        if (pid == 0) // 子进程
        {
            std::cout << "children: " << getpid() << " process running" << std::endl;
            sleep(1);
            exit(0);
        }
    }
    while (1)//父进程
    {
        otherthing();
        sleep(1);
    }
}

在这里插入图片描述

默认处理和signal函数处理

SIGCHLD的默认处理是隐式忽略,但是和signal(SIGCHLD, SIG_IGN)显示忽略的意义不一样,虽然都可以避免僵尸进程进程的产生。
显式忽略 SIGCHLD 的主要目的是确保子进程资源被正确回收,尤其是在以下场景中:

  • 父进程不关心子进程的退出状态:显式忽略 SIGCHLD 可以避免僵尸进程的产生,而无需调用 wait() 或 waitpid()。
  • 跨平台兼容性:在某些系统中,SIGCHLD 的默认行为可能不是忽略,显式忽略可以确保一致的行为。

显式忽略与默认忽略的区别:

  • 显式忽略 SIGCHLD 时,内核仍然会生成 SIGCHLD 信号,但父进程不会处理它。
  • 默认忽略时,内核不会生成 SIGCHLD 信号。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值