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

编译创建子进程的C代码后Linux系统意外关机的原因排查

代码导致Linux系统意外关机的原因及修复方案

我编写了一段简单的C代码,尝试创建10个子进程,让每个子进程独立执行打印时间的任务,之后在父进程中终止所有子进程。但运行该代码时,子进程输出内容后Linux系统会意外关机,需要重新输入用户密码启动。代码如下:

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


int main() {
    pid_t pids[10];
    int i;
    int n= 10;

    for (i= 0; i<n; ++i) {
        if ((pids[i] = fork()) <0) {
            perror("fork");
            abort();
        } 

        else if (pids[i] == 0) {
            struct timeval tv;
            time_t t;
            struct tm*info;
            char buffer[64];

            gettimeofday(&tv,NULL);
            t = tv.tv_sec;
            info = localtime(&t);

            sleep(1);
            printf("CHILD PID: %d and the time is %s\n",getpid(),asctime(info));
        }
    }

    int status;
    pid_t pid;
    sleep(5);
    while (n >0) {
        pid = wait(&status);

        kill((long)pid, SIGTERM);
        printf("CHILD %d killed.",pid);
        --n;
    }

}

核心问题:子进程未退出引发「fork风暴」

  • 子进程执行完printf后没有调用exit()或_exit(),会继续执行父进程的后续代码——也就是for循环的剩余部分。每个子进程都会继续创建新的子进程,短时间内系统会被海量进程占满,直接耗尽CPU、内存等核心资源,触发系统OOM(内存不足)机制,甚至导致系统崩溃重启。
  • 父进程的wait()逻辑完全无效:wait()返回的是已经终止的子进程PID,此时调用kill()没有任何意义;如果PID被系统复用,还可能误杀其他正常进程,加重系统异常。

修复方案

  1. 子进程执行完任务后立即退出,避免执行父进程的后续代码。
  2. 父进程无需在wait()后调用kill(),直接等待子进程自然终止即可;如果需要主动终止子进程,应先发送信号再等待退出状态。

修复后的代码(等待子进程自然终止)

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

int main() {
    pid_t pids[10];
    int i;
    int n = 10;

    for (i = 0; i < n; ++i) {
        if ((pids[i] = fork()) < 0) {
            perror("fork");
            abort();
        } else if (pids[i] == 0) {
            struct timeval tv;
            time_t t;
            struct tm* info;

            gettimeofday(&tv, NULL);
            t = tv.tv_sec;
            info = localtime(&t);

            sleep(1);
            printf("CHILD PID: %d and the time is %s\n", getpid(), asctime(info));
            // 子进程执行完任务后立即退出,避免执行父进程代码
            exit(EXIT_SUCCESS);
        }
    }

    int status;
    pid_t pid;
    sleep(5);
    printf("开始等待子进程终止...\n");
    while (n > 0) {
        pid = wait(&status);
        if (pid == -1) {
            perror("wait");
            break;
        }
        printf("CHILD %d 已终止。\n", pid);
        --n;
    }

    return 0;
}

主动终止子进程的版本

如果需要父进程主动发送终止信号,可修改父进程逻辑:

// 替换原父进程等待代码为:
sleep(5);
printf("主动终止所有子进程...\n");
for (i = 0; i < 10; ++i) {
    if (pids[i] > 0) { // 确保是有效的子进程PID
        kill(pids[i], SIGTERM);
        printf("已发送终止信号给 CHILD %d\n", pids[i]);
    }
}

// 等待所有子进程退出
int status;
pid_t pid;
while ((pid = wait(&status)) != -1) {
    printf("CHILD %d 已终止。\n", pid);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 23:41:10