如何使用C语言在Linux上编程地杀死一个进程树

6
我正在尝试编写一个函数,它会生成一个子进程,让其运行一段时间,如果在规定时间内未完成,则强制终止该进程:
int sysExecTimeout(const char * exePath, int timeoutSec);

在这个函数中,我使用forkexecl来生成子进程,并在超时后使用kill(pid, SIGTERM)kill(pid, SIGKILL)在两秒钟内确保子进程死亡。
pid_t pid = fork();

if(pid == 0) {
    execl("/bin/sh", "sh", "-c", exePath);
    exit(127);
} else if(pid != -1) {
    // timeout code
    if(timeout) {
        kill(pid, SIGTERM);
        sleep(2);
        kill(pid, SIGKILL);
    }
}

我正在使用Linux,似乎当父进程死亡时,子进程不会自动终止。因此,这两个“kill”调用将仅杀死“/bin/sh”进程,并使“exePath”命令继续运行,因为它是“/bin/sh”的子进程。
我正在尝试编写“sysExecTimeout”函数,以便它可以杀死以“pid”为根的整个进程树,“pid”是从“pid = fork()”获得的PID。
我需要这样做是因为“exePath”命令将生成其他命令,这些命令也可以生成其他命令,这些命令可能会卡住并消耗资源。
我无法控制执行的“exePath”二进制文件/脚本,因此我不能在其中编写自己的父进程死亡所以杀死子进程的逻辑。
我尝试使用“kill(0,SIGTERM)”,它几乎完成了任务,但它还杀死了我的进程:)
我想知道是否有一个标志我可以在C中以编程方式打开,它说“嘿,当我死亡时,带上所有我的孩子并杀死他们,并针对他们的孩子递归重复” ,以便从该程序开始的整个进程树都会死亡(假设可以跟踪PID / PPID链)。
我可以在这里使用该标志:
if(pid == 0) {
    turnOnRecursiveDeathFlag();

    system(exePath);
    //execl("/bin/sh", "sh", "-c", exePath);
    exit(127);
}

有没有方法可以做到这一点?我已经搜索了一段时间,但我能找到的都是使用 ps -ef 或修改正在运行的子进程等技巧。


2
} else if(pid == -1) {:这表示fork()出现问题,而不是子进程。 - xtof pernod
是的,抱歉,那是一个打错字 :) - Alin Tomescu
1个回答

16

在子进程中使用setpgid将其GPID设置为自己的PID。然后父进程可以使用kill(-pid,...)向整个进程组发送信号。

pid_t pid = fork();

if(pid == 0) {
    setpgid(0, 0);
    execl("/bin/sh", "sh", "-c", exePath);
    exit(127);
} else if(pid == -1) {
    // timeout code
    if(timeout) {
        kill(-pid, SIGTERM);
        sleep(2);
        kill(-pid, SIGKILL);
    }
}

应该就这样了。

还有一件事,当你生成一个shell时,确保它没有启用作业控制。否则,它将创建自己的进程组。你的"/bin/sh -c"很好。


太好了,这似乎有效,谢谢!我不确定进程组ID的问题是什么(那只是进程的GID吗?),但我正在研究它。 - Alin Tomescu
顺便说一下,由于我无法编辑您的帖子,您应该将setgpid更改为setpgid,这似乎是正确的名称。 - Alin Tomescu
我为他修复了这个问题@AlinTomescu...或者我猜它正在被审核中。 - Mgamerz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接