【问题标题】:Handle end of execution处理执行结束
【发布时间】:2013-05-25 22:42:56
【问题描述】:

我正在使用很多叉子制作一个小程序。第一个父母必须等待每个孩子。 只有一个孩子很容易,有孩子结束信号(SIGCLHD)。但是,如果我的第一个孩子在最后一个孩子之前结束怎么办?我的主程序在everychilds 结束之前运行,我需要主程序等待孩子。

每个孩子都以执行另一个程序结束,这解释了为什么我不能与信号量之类的东西同步。

// Working pretty good
execvp(
    c->command_name, /* program to execute */
    c->argv          /* argv of program to exécuter */
);

这是我的“分叉结构”:

main
 |
 |------
 |     |
 |     |
 |     |------
 |     |     |
 |    EOE    |
 |           |
 |          EOE
 |
 |
EOE

传说:

  • EOE 的意思是“执行结束
  • 最上面一行是时间线
  • 左边的每一步都是新的孩子。
  • 每个竖条代表一个条的执行

谢谢!

【问题讨论】:

    标签: c system posix fork


    【解决方案1】:

    要找出哪些子进程已终止,请在您的 SIGCHLD 处理程序中使用 waitpid

    /* SIGCHLD handler. */
    static void sigchld_hdl (int sig)
    {
        pid_t child_pid;
    
        /* Wait for all dead processes.
         * We use a non-blocking call to be sure this signal handler will not
         * block if a child was cleaned up in another part of the program. */
        while ((child_pid = waitpid(-1, NULL, WNOHANG)) > 0) {
              // child_pid contains the terminated child process' pid
        }
    }
    

    有关更多详细信息和此 sn-p 所基于的 sscce,请查看 example's source

    编辑:

    所以问题是如何不仅等待孩子,而且等待所有后代。

    在伪代码中:

    int alive_descendants = 0;
    
    sigchld_handler() {
        decrement alive_descendants for each zombie;
    }
    
    int main() {
         setup-sigchld-handler;
    
         int fd[2];
         if (pipe(fd)) { error }
    
         to create a child:
             write a single byte to fd[1]
             fork off the child
             in the child process:
                 close(fd[0]);
                 to create child:
                      write a single byte to fd[1]
                      fork off the child
                      ...
    
         in the root process:
             close(fd[1]);
             for each byte read from fd[0], increment alive_descendants
             if alive_descendants == 0 and fd[0] is empty:
                  ascertain that all descendants have terminated
                  close(fd[0]);        
    }
    

    【讨论】:

    • 哪个编译器允许您在while 循环的条件下声明变量? C 标准不允许这样做——尽管 C++ 标准允许这样做。
    • 您好,抱歉。也许我解释得不好。我编辑了我的帖子。 (我试过你的解决方案,第一个孩子结束后的while结束)
    • @Nek sigchld_hdl不一定一次运行一次处理所有的children,可能会被调用多次,每次只处理一部分children。
    • 我尝试了您的解决方案。使用信号量停止主进程的执行,信号使主进程再次运行。第一个信号,我不知道如何检测我将拥有的“多少”信号......
    • @Nek 哦,我明白了,您需要等待孙进程。创建一个管道怎么样,写端传播到所有后代进程,根进程保持读端?
    【解决方案2】:

    你试过了吗

    // for each child spawned:
    children[i] = fork(); // children is an array of pid_t
    if (children[i] == 0) {
        execvp(
            c->command_name, /* programme à exécuter */
            c->argv          /* argv du programme à exécuter */
        );
    
    // parent process keeps doing its thing, and then
    for (i = 0; i < NUMBER_OF_CHILDREN; i++) {
        waitpid(children[i], NULL, 0);
    }
    

    【讨论】:

    • 这迫使父母等待每个孩子按照他们被创造的顺序死亡。通常最好等待“任何”孩子死亡,然后将其从等待列表中删除。
    • 我认为最终解决方案更像这样。我应该能够与所有孩子共享一个数组,这些孩子将为数组中的每个分叉添加新的 pid。像 mmap 这样的东西应该可以工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-05
    • 1970-01-01
    • 1970-01-01
    • 2016-09-08
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    相关资源
    最近更新 更多