【问题标题】:Why does my waitpid() not wait for child after making a background process为什么我的waitpid()在进行后台进程后不等待孩子
【发布时间】:2021-06-03 19:05:34
【问题描述】:

我编写了这个简单的程序,它无休止地要求用户输入,然后使用 fork() 创建另一个进程来执行“ls -la”。

当用户输入为0时,进程被创建为后台进程。如果用户输入的是其他内容,则父进程等待子进程终止。

在每次迭代中,僵尸进程都会终止。这似乎工作得很好

这段代码的问题是:创建后台进程时,任何后续进程的父进程都不再等待。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>


void delete_zombies(void)
{
    pid_t kidpid;
    int status;

    while ((kidpid = waitpid(-1, &status, WNOHANG)) > 0)
    {
        printf("Child %ld terminated\n", kidpid);
    }
}

int main() {

    int runBGflag =0;

    while(1)
    {
        scanf("%d",&runBGflag); //get user input
        if (runBGflag==0) printf("making a child process and wait for it to finish\n");
        else printf("making a background process\n");
        pid_t pid;   //fork
        pid = fork();




        if (pid > 0 && runBGflag==0) //Parent process. Waits for child termination and prints exit status
        {
            int status;
            if (waitpid(-1, &status, 0) == pid && WIFEXITED(status))
            {
                printf("child dead. parent continues\n");
            }
        }

        if (pid == 0)  //Child process. Executes commands and prints error if something unexpected happened
        {
            execlp ("ls", "-la", NULL);
            printf ("exec: %s\n", strerror(errno));
            exit(1);
        }

        delete_zombies();
    }

}

我期待输出

例如我希望输入 010 后有以下输出

0
making a child process and wait for it to finish
CMakeCache.txt  cmake_install.cmake  sigchild      Testing
CMakeFiles  Makefile         sigchild.cbp
child dead. parent continues
1
making a background process
CMakeCache.txt  cmake_install.cmake  sigchild      Testing
CMakeFiles  Makefile         sigchild.cbp
0
making a child process and wait for it to finish
CMakeCache.txt  cmake_install.cmake  sigchild      Testing
CMakeFiles  Makefile         sigchild.cbp
child dead. parent continues

但是我只得到

0
making a child process and wait for it to finish
CMakeCache.txt  cmake_install.cmake  sigchild      Testing
CMakeFiles  Makefile         sigchild.cbp
child dead. parent continues
1
making a background process
CMakeCache.txt  cmake_install.cmake  sigchild      Testing
CMakeFiles  Makefile         sigchild.cbp
0
making a child process and wait for it to finish
CMakeCache.txt  cmake_install.cmake  sigchild      Testing
CMakeFiles  Makefile         sigchild.cbp

【问题讨论】:

    标签: c process


    【解决方案1】:

    如果您运行子程序是为了等待它,您实际上并没有等待那个特定的子程序,而是等待任何子程序。如果有一个先前已启动且未等待的子代,则可以将其收集起来。

    你想要更像这样的东西:

            if (pid > 0 && runBGflag==0) //Parent process. Waits for child termination and prints exit status
            {
                int status;
                if (waitpid(pid, &status, 0) == pid && WIFEXITED(status)) // CHANGED
                {
                    printf("child dead. parent continues\n");
                }
            }
    

    还要注意WIFEXITED(status) 测试报告的进程是否正常终止。这不包括那些被信号杀死的人,尽管如此,他们还是一样死了。它也不包括那些已经停止但没有终止的——那些没有死,但你的程序无论如何都会停止等待它们。

    【讨论】:

      【解决方案2】:

      您正在这部分等待任何个子进程:

      if (pid > 0 && runBGflag==0) //Parent process. Waits for child termination and prints exit status
      {
          int status;
          if (waitpid(-1, &status, 0) == pid && WIFEXITED(status))
          {
              printf("child dead. parent continues\n");
          }
      }
      

      因此,这里可能会更正“后台进程”而不是新进程。 “后台进程”应该与新进程具有不同的 pid,因此可能不会打印消息“child dead...”。

      这可以通过插入如下调试打印语句来验证:

      if (pid > 0 && runBGflag==0) //Parent process. Waits for child termination and prints exit status
      {
          int status;
          pid_t ret = waitpid(-1, &status, 0);
          printf("debug: expected %d, actual %d\n", (int)pid, (int)ret);
          if (ret == pid && WIFEXITED(status))
          {
              printf("child dead. parent continues\n");
          }
      }
      

      为避免这种情况,您应该通过waitpid() 的第一个参数指定要等待的进程,如下所示:

      if (pid > 0 && runBGflag==0) //Parent process. Waits for child termination and prints exit status
      {
          int status;
          if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
          {
              printf("child dead. parent continues\n");
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2015-02-24
        • 1970-01-01
        • 2014-11-08
        • 1970-01-01
        • 2020-01-15
        • 2016-03-19
        • 2013-01-10
        • 1970-01-01
        相关资源
        最近更新 更多