以下代码启动一个冗长的 nmap 进程,然后主程序尝试终止它。我从 shell 运行它,并且还在另一个窗口中运行 GTOP,只是为了看看是否一切都成功。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/wait.h>
int main()
{
int ret,childpid=0;
ret = fork();
if (ret == 0)
{
printf("Here A %d.. \n", ret);
char *params[5] = {"nmap","-sS","-A","192.168.0.1/24",0}; //cmd params filled
childpid = execv( "/usr/bin/nmap" , params); //parameters for cmd
printf("\n child exiting (%d) (%d).. \n", childpid,errno); //on successful execution of cmd, this exit never appears
}
else
{
childpid=ret;
printf("parent exiting\n");
if (childpid!=0)
{
printf("child %d about to be killed wait 15 so that htop has time to see it\n",childpid);
sleep(15);
kill(childpid, SIGTERM);
sleep(2);
kill(childpid, SIGKILL);
printf("killed wait 15 HTOP should have time to update\n");
sleep(15);
}
}
return 1;
}
HTOP 看到 nmap 正在启动,但是当我终止该进程时,它仍然显示在 HTOP 显示中。当我的主程序退出时,HTOP 将从进程列表中删除 nmap。我做错了什么或者误解了 HTOP 吗?
答案1
您生成了一个子进程,将其杀死,但没有继续wait(2)
执行。该进程现在是一个僵尸进程,为它的父进程徘徊。当父进程死亡时,僵尸进程就成为孤儿进程,由 init 来处理。从man 2 wait
在 Linux 上:
在子进程终止的情况下,执行等待允许系统释放与子进程相关的资源;如果不执行等待,则终止的子进程仍处于“僵尸”状态(请参阅下面的注释)。
并从注释中:
终止但尚未等待的子进程将成为“僵尸”。内核维护有关僵尸进程的最小信息集(PID、终止状态、资源使用信息),以便允许父进程稍后执行等待以获得有关子进程的信息。只要僵尸进程没有通过等待从系统中移除,它就会消耗内核进程表中的一个槽,如果该表已满,则无法创建更多进程。如果父进程终止,则其“僵尸”子进程(如果有)由 init(1) 采用(或由通过使用 pctl(2) PR_SET_CHILD_SUBREAPER 操作定义的最近的“子收割者”进程); init(1) 自动执行等待以删除僵尸。
所以,wait()
对于子进程来说,还是会一直挂着,直到父进程死掉。
答案2
我想我找到了解决方案。如果我按如下方式更改kill部分:
...
{
printf("child %d about to be killed wait 15 so that htop has time to see it\n",childpid);
sleep(15);
kill(childpid, SIGKILL);
waitpid(childpid,&ret,WUNTRACED);
}
}
return 1;
}
添加 waitpid 似乎可以清除 HTOP 中的进程。如果有人知道任何警告(为什么我应该使用 SIGKILL 而不是 SIGTERM 或者我应该使用 WUNTRACED 以外的其他东西?)请让 Mr 知道。