英文:
Why is the child process a zombie after kill() it
问题
我有一个多进程程序。简要说明问题,子进程将被阻塞,主进程判断子进程是否仍然存在,如果存在则杀死子进程。
我的代码如下:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <sys/socket.h>
#include <string.h>
#define TIME_OUT 3
int get_current_time()
{
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
return t.tv_sec;
}
void child_process_exec()
{
int fd = open("./myfifo", O_WRONLY); // myfifo 是一个命名管道,在这里会被阻塞。
sleep(10);
}
void parent_process_exec(pid_t workProcessId)
{
int status;
int childRes;
int lastHeartBeatTime = get_current_time();
while (1)
{
sleep(1);
if (get_current_time() - lastHeartBeatTime > TIME_OUT)
{
childRes = waitpid(workProcessId, &status, WNOHANG);
if (childRes == 0)
{
printf("kill process\n");
printf("kill get %d\n", kill(workProcessId, SIGTERM));
}
workProcessId = fork();
if (workProcessId > 0)
{
lastHeartBeatTime = get_current_time();
}
else
{
printf("start up child process again\n");
child_process_exec();
return;
}
}
}
}
int main()
{
pid_t workProcessId = fork();
if (workProcessId > 0)
{
parent_process_exec(workProcessId);
}
else
{
child_process_exec();
}
return 0;
}
但是我使用 ps
命令在终端中获取子进程是 <defunct>
。为什么杀死子进程后子进程会成为僵尸进程?如何干净地杀死子进程?
英文:
I have a multi-processes program. To briefly illustrate the problem, the child process will be only blocked and the main process judge whether the child process still exists, if exists the parent
process kill the child process.
My codes are as below:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <sys/socket.h>
#include <string.h>
#define TIME_OUT 3
int get_current_time()
{
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
return t.tv_sec;
}
void child_process_exec()
{
int fd = open("./myfifo", O_WRONLY); // myfifo is a named pipe, here will be blocked.
sleep(10);
}
void parent_process_exec(pid_t workProcessId)
{
int status;
int childRes;
int lastHeartBeatTime = get_current_time();
while(1) {
sleep(1);
if (get_current_time() - lastHeartBeatTime> TIME_OUT) {
childRes = waitpid(workProcessId, &status, WNOHANG);
if(childRes == 0) {
printf("kill process\n");
printf("kill get %d\n", kill(workProcessId, SIGTERM));
}
workProcessId = fork();
if(workProcessId > 0) {
lastHeartBeatTime = get_current_time();
} else {
printf("start up child process again\n");
child_process_exec();
return;
}
}
}
}
int main()
{
pid_t workProcessId = fork();
if (workProcessId > 0) {
parent_process_exec(workProcessId);
} else {
child_process_exec();
}
return 0;
}
But I use ps
get the child process is <defunct>
in the terminal. Why is the child process a zombie after kill() it? How can I kill the child process cleanly?
答案1
得分: 0
-
在 t+3 秒时,您调用
waitpid(..., WNOHANG)
,它立即返回,不等待子进程结束,正如childRes == 0
所示。您终止了第一个子进程,然后用第二个子进程的 PID 覆盖了workProcessId
。反复进行这个过程。这意味着在子进程终止后从未调用过waitpid()
,在t=T
时,您将拥有T/3
个僵尸子进程。最简单的修复方法是将WNOHANG
更改为 0,以便父进程阻塞等待子进程。您也可以通过使用wait()
阻塞等待任何子进程来获得类似的效果。 -
您可能希望修复
parent_process_exec()
中的逻辑,以便它不会无条件地fork一个新的子进程。 -
在Linux上,我不得不包括
signal.h
以使用kill()
。 -
将
int workProcessId
更改为pid_t workProcessId
。 -
open()
的第二个参数应该是一个int
而不是一个字符串,所以您应该使用O_WRONLY
而不是"O_WRONLY"
。始终检查返回值。
英文:
-
At t+3s you call
waitpid(..., WNOHANG)
which immidiately returns without reaping the child as is evident bychildRes == 0
. You kill the first child then overwriteworkProcessId
with pid of the 2nd child. Rinse and repeat. This meanswaitpid()
is never called after a child has terminated, and att=T
you end up withT/3
zombie child processes. The easiest fix would be to changeWNOHANG
to 0 so parent blocks waiting for child. You would get similar effect by just usingwait()
to block waiting for any child.Alternatively, maintain an array of pid_t to hold each of the children that haven't been reaped then. Then loop that array with
waithpid(..., WNOHANG)
. -
You probably want to fix the logic in
parent_process_exec()
so it doesn't unconditionally fork a new child. -
On Linux, I had to include
signal.h
forkill()
. -
Change
int workProcessId
topid_t workProcessId
. -
The 2nd argument to
open()
is anint
not a string so you want to useO_WRONLY
not"O_WRONLY"
. Always check return values.
答案2
得分: 0
根据这个来自@Useless的回答,我在杀死子进程后添加了wait()
,现在父进程回收了子进程。像这样:
if(childRes == 0) {
printf("杀死进程\n");
printf("杀死获取 %d\n", kill(workProcessId, SIGTERM));
wait(NULL); // 返回子进程的pid
}
我知道僵尸进程只是一个进程ID,它是无害的,但我认为应该有一种方法来杀死子进程。但在父进程杀死子进程后,还是留下了一个僵尸进程,这真的让我困惑。
英文:
According to this from @Useless, I add wait()
after kill the child process, now parent reap the child process. Like this
if(childRes == 0) {
printf("kill process\n");
printf("kill get %d\n", kill(workProcessId, SIGTERM));
wait(NULL); // return the child process pid
}
I know a zombie process is just a pid, it is harmless, but I think there should be a method to kill child process. But there is a zombie left after the parent process kill its child, this really confuse me.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论