c++ - 同时fork 100个进程,有时有些进程会变成僵尸进程

标签 c++ linux fork zombie-process waitpid

我尝试在以下代码中同时启动 100 个进程:

int cnt = 0;

void sig_handler(int signo) {
    pid_t pid;
    int stat;
    pid = wait(&stat);
    cout << "cnt:" << ++cnt << ", pid:" << pid << " signal:" << signo << endl;
}

int main() {
    signal(SIGCHLD, sig_handler);
    for (int i = 0; i < 100; ++i) {
        if (fork() == 0) {
            sleep(1);
            exit(0);
        }
    }
    printf("wait\n");
    while (1);
}

我在sig_handler中捕获SIGCHLD信号,结果不同:有时所有进程都返回OK;有时 1 到 4 个进程会成为僵尸进程。

[vinllen@my-host]$ ./a.out
wait
cnt:1, pid:4383 signal:17
cnt:2, pid:4384 signal:17
cnt:3, pid:4385 signal:17
cnt:4, pid:4386 signal:17
cnt:5, pid:4387 signal:17
…
cnt:94, pid:4476 signal:17
cnt:95, pid:4477 signal:17
cnt:96, pid:4478 signal:17
cnt:97, pid:4479 signal:17
cnt:98, pid:4480 signal:17

[vinllen@my-host ~]$ ps aux | grep a.out
Vinllen       4382 96.2  0.0  13896  1084 pts/8    R+   15:14   0:03 ./a.out
Vinllen       4481  0.0  0.0      0     0 pts/8    Z+   15:14   0:00 [a.out] <defunct>
Vinllen       4482  0.0  0.0      0     0 pts/8    Z+   15:14   0:00 [a.out] <defunct>
Vinllen       4493  0.0  0.0 105300   864 pts/9    S+   15:14   0:00 grep a.out

我猜原因是多个进程同时退出并触发了某些东西。谁能给我详细的原因并告诉我如何解决这个问题。

据我了解,双 fork 和忽略SIGCHLD是解决这个问题的两种有效方法。但是,如何解决此代码中仍然调用 wait 的问题。

最佳答案

信号不排队。如果在 SIGCHLD 处于待处理状态时引发 SIGCHLD(可能是当您的代码位于 write 系统调用中时),程序将仅收到一个通知。

处理这个问题的正确方法是在处理程序中循环,直到所有完成的子项都被收获:

void sig_handler(int signo) {
    pid_t pid;
    int stat;
    while ((pid = waitpid(-1, &stat, WNOHANG) > 0)
    if (WIFEXITED(stat))
    {
        // Don't actually do this: you should
        // avoid buffered I/O in signal handlers.
        std::cout << "count:" << ++cnt
                  << ", pid:" << pid
                  << " signal:" << signo
                  << std::endl;
    }
}

正如评论中提到的,您应该坚持记录的 async-signal-safe functions在信号处理程序中。缓冲 I/O(包括使用 std::cout)可能存在风险,因为信号处理程序在操作其内部结构时可能会被调用。避免问题的最佳方法是限制自己使用 volatile sig_atomic_t 变量与主代码进行通信。

关于c++ - 同时fork 100个进程,有时有些进程会变成僵尸进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45454058/

相关文章:

c++ - 压缩后将哈夫曼树写入文件

c++ - 如何将 std::variant 类型与 %type 指令一起使用

linux - Linux (Bash) 中变量的多路径添加

c - vfork 永不返回

c++ - 在 gcc 和 MSVC/clang 之间使用 C++20 重载模板化相等比较运算符的不同结果

c++ - 如何使用 DetourAttachEx 创建蹦床函数? (有MS绕路)

linux - 无法使用 +x 权限执行脚本文件,即使使用 sudo

python - 在尝试无效命令时,终端中的 Ctrl+C 生成 python 回溯

c - Fork, C 后无法杀死父进程

c - fork()系统调用的工作(C程序)