我需要分叉许多生命周期较短的进程。 (但我不想等到它完成。就让它运行吧。)。一段时间后,我在执行 fork 时收到错误(errno == 11)。看起来分叉的进程仍然存在(至少它们在 htop 中可见)。
例如,请考虑以下示例。我想分叉一个进程,然后不久后退出它。
#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;
}
一开始它运行正确。几分钟后我只收到错误:
无法启动进程 错误号:11
我无法再开始新的分叉了。 我在 Ubuntu 22.04 上运行它
当进程终止时,其PID和退出状态仍然作为进程表中的记录保留。这就是所谓的僵尸进程。您可以通过使用
wait()
函数系列之一读取其状态来删除它,如兄弟答案中所述。
如果您不需要关心子进程的状态,您可以允许
init
读取它们的状态并清理表。当父进程终止时,init
(PID 为 1 的进程)默认成为其所有子进程的父进程。因此,您可以使用双叉使 init
成为进程的父进程:
void RunProc(void)
{
pid_t pid = fork();
if (pid == -1) {
perror("fork()");
return;
}
if (pid == 0)
{
// first level child
pid_t pid = fork();
if (pid == -1) {
perror("fork()");
_exit(1);
}
if (pid != 0) {
// first level child just terminates
_exit(0);
}
// second level child
puts("fork with success");
_exit(0);
}
// wait for first level child
if (waitpid(pid, NULL, 0) == -1) {
perror("wait()");
}
}