为什么在使用kill()后,子进程会变成僵尸进程?

huangapple go评论60阅读模式
英文:

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 &lt;stdio.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;time.h&gt;
#include &lt;errno.h&gt; 
#include &lt;sys/socket.h&gt; 
#include &lt;string.h&gt;

#define TIME_OUT 3 

int get_current_time()
{
    struct timespec t;
    clock_gettime(CLOCK_REALTIME, &amp;t);
    return t.tv_sec;
}

void child_process_exec() 
{
    int fd = open(&quot;./myfifo&quot;, 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&gt; TIME_OUT) {
            childRes = waitpid(workProcessId, &amp;status, WNOHANG);
            if(childRes == 0) {  
                printf(&quot;kill process\n&quot;); 
                printf(&quot;kill get %d\n&quot;, kill(workProcessId, SIGTERM));
            }
			
            workProcessId = fork();
            if(workProcessId &gt; 0) {
                lastHeartBeatTime = get_current_time();
            } else {
                printf(&quot;start up child process again\n&quot;);
                child_process_exec();
                return;
            }
        }
    }
}

int main()
{
    pid_t workProcessId = fork();
    if (workProcessId &gt; 0) {
        parent_process_exec(workProcessId);
    } else {
        child_process_exec();
    }
    
    return 0;
}

But I use ps get the child process is &lt;defunct&gt; in the terminal. Why is the child process a zombie after kill() it? How can I kill the child process cleanly?

答案1

得分: 0

  1. 在 t+3 秒时,您调用 waitpid(..., WNOHANG),它立即返回,不等待子进程结束,正如 childRes == 0 所示。您终止了第一个子进程,然后用第二个子进程的 PID 覆盖了 workProcessId。反复进行这个过程。这意味着在子进程终止后从未调用过 waitpid(),在 t=T 时,您将拥有 T/3 个僵尸子进程。最简单的修复方法是将 WNOHANG 更改为 0,以便父进程阻塞等待子进程。您也可以通过使用 wait() 阻塞等待任何子进程来获得类似的效果。

  2. 您可能希望修复 parent_process_exec() 中的逻辑,以便它不会无条件地fork一个新的子进程。

  3. 在Linux上,我不得不包括 signal.h 以使用 kill()

  4. int workProcessId 更改为 pid_t workProcessId

  5. open() 的第二个参数应该是一个 int 而不是一个字符串,所以您应该使用 O_WRONLY 而不是 "O_WRONLY"。始终检查返回值。

英文:
  1. At t+3s you call waitpid(..., WNOHANG) which immidiately returns without reaping the child as is evident by childRes == 0. You kill the first child then overwrite workProcessId with pid of the 2nd child. Rinse and repeat. This means waitpid() is never called after a child has terminated, and at t=T you end up with T/3 zombie child processes. The easiest fix would be to change WNOHANG to 0 so parent blocks waiting for child. You would get similar effect by just using wait() 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).

  2. You probably want to fix the logic in parent_process_exec() so it doesn't unconditionally fork a new child.

  3. On Linux, I had to include signal.h for kill().

  4. Change int workProcessId to pid_t workProcessId.

  5. The 2nd argument to open() is an int not a string so you want to use O_WRONLY not &quot;O_WRONLY&quot;. 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(&quot;kill process\n&quot;); 
    printf(&quot;kill get %d\n&quot;, 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.

huangapple
  • 本文由 发表于 2023年7月3日 14:59:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76602504.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定