You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确fork并处理进程以避免EAGAIN错误(errno=11)

问题:fork大量短生命周期进程后出现errno=11错误

我需要fork大量短生命周期进程(无需等待其完成,只需让它自行运行)。运行一段时间后,执行fork时出现错误,errno等于11,且通过htop可以看到此前fork出的进程仍然存在。运行环境为Ubuntu 22.04。

示例代码

#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <errno.h>
#include <signal.h>

void RunProc(){   
    pid_t pid = fork();
    if(pid == 0)
    {
        puts("fork with success");
        //no needed to reproduce issue. Used in my code to run some commands.
        //execvp()             
        exit(0);
    }
    else if (pid == -1) {
        printf("Could not start process\n");
        printf("Errno: %d\n", errno);
    }
    else {
    }
}
 
int main()
{
    while(true){
        RunProc();
    }

    int res = 0;
    int i = 5;
    res = scanf("%d", &i);
    res = printf("End of program %d\n", i);
    return res;
}

错误输出

Could not start process
Errno: 11

解决方案

问题根源

errno=11对应EAGAIN,表示系统暂时无法分配足够资源创建新进程。核心原因是父进程未处理子进程的退出状态,导致子进程退出后变成僵尸进程(zombie process)。僵尸进程会持续占用系统进程表条目,当进程表被耗尽时,就无法再fork新进程,htop中看到的“仍存在”的进程就是这些僵尸进程。

修复方案1:忽略SIGCHLD信号(推荐)

如果不需要获取子进程的退出状态,直接告诉内核自动回收子进程是最简单的方式。在main函数开头添加以下代码:

signal(SIGCHLD, SIG_IGN);

内核会在子进程退出时自动清理其资源,不会产生僵尸进程。

修复方案2:主动回收僵尸进程

如果后续需要处理子进程的退出状态,可以通过waitpid非阻塞地回收已退出的子进程。修改RunProc函数:

void RunProc(){   
    pid_t pid = fork();
    if(pid == 0)
    {
        puts("fork with success");
        //execvp()             
        exit(0);
    }
    else if (pid == -1) {
        printf("Could not start process\n");
        printf("Errno: %d\n", errno);
    }
    else {
        // 非阻塞回收所有已退出的子进程
        while (waitpid(-1, NULL, WNOHANG) > 0);
    }
}

也可以注册SIGCHLD信号处理函数,在信号回调中调用wait或waitpid回收僵尸进程。

验证修复

修改代码后重新运行,使用ps aux | grep 'Z'查看是否还有僵尸进程。如果僵尸进程不再积累,说明修复生效,fork可以正常创建新进程。

内容的提问来源于stack exchange,提问作者AdamF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 00:37:43