【问题标题】:Creating multiple child processes in C for one parent在 C 中为一个父进程创建多个子进程
【发布时间】:2014-05-11 13:44:07
【问题描述】:

所以我一直在为我的操作系统类编写代码,在我的项目中,我必须在命令行上为每个文件创建一个新的子进程,并将信息从子进程传递到父进程。我们应该重新创建 Unix 的 wc 实用程序(我已经处理了这部分)。

到目前为止我尝试过的是:

            for(i=0; i<argcount; i++){
                    int pid;
                    pid = fork();
                    if(pid == 0){
                            /* Child Process */
                            /* Close read pipes */
                            close(l_pipe[0]);
                            close(w_pipe[0]);
                            close(c_pipe[0]);
                            wc(lflag, wflag, cflag, filenames[i]);
                    } else {
                            /* Parent Process for piping */
                            /* Close write pipes */
                            close(l_pipe[1]);
                            close(w_pipe[1]);
                            close(c_pipe[1]);

                            /* Read from pipes */
                            read(l_pipe[0], &buffer, sizeof(count_t));
                            lines+=buffer;

                            read(w_pipe[0], &buffer, sizeof(count_t));
                            words+=buffer;

                            read(c_pipe[0], &buffer, sizeof(count_t));
                            bytes+=buffer;
                    }
            }

但是,这会产生与孩子一样多的父母,这显然是错误的。我不确定我应该在哪里分叉。我必须在子进程和父进程之间使用管道,并且我确信父进程需要 read() 的次数与子进程 write() 的次数一样多。

感谢您提供的任何建议。

【问题讨论】:

    标签: c children


    【解决方案1】:

    除了Greg Hewgill 在他的answer 中提出的问题,我还观察到以下问题:

    1. 您可以让循环分叉并运行子进程,而父部分只是返回到循环的下一次迭代。
    2. 然后您将有一个循环从管道中读取。
    3. 在该循环之前,父进程将关闭所有三个管道的写入端(否则它永远不会在管道上看到 EOF)。
    4. 从管道读取的循环应该依次从每个管道读取,而不是依次排空每个管道。
    5. 我假设你有count_t buffer;——它有助于显示变量声明。如果你有某种char buffer[sizeof(count_t)],那么你就会遇到各种大大小小的问题。
    6. 在您当前的方案中创建第二个孩子时,管道的写入端全部关闭,因此第二个和后续孩子将无法向父母发送任何内容。您必须移动三个调用以关闭管道的写入端,使其位于循环之外。
    7. 您的管道必须位于全局变量中,以便wc 函数可以使用它们。这不是世界末日,但避免全局变量通常更整洁。这是一个二阶问题;您还有其他更重大的问题需要先解决。
    8. 如果您需要将大小与单个文件相关联,则需要做更多的簿记工作。目前,您只汇总总计。在这种情况下,您当前的同步设计可能是合适的。如果做不到这一点,你会让孩子们在一个操作中写一个 PID 或另一个 ID 号加上管道上的计数(以确保操作是原子的)。单个写入操作不会交错,除非它们对于管道的内部缓冲区来说太大了,这对于几个整数来说不是问题。

    【讨论】:

    • 绝对是 count_t 缓冲区。这看起来很有帮助,我会考虑你的建议。此外,我的 wc() 在标准输入上打印自己的个人计数,通过管道发送它们,并打印在其中调用它的进程的 PID。
    【解决方案2】:

    有几件事我马上就注意到了。

    • 在您的子进程分支中,您不会在 wc() 之后调用 _exit()。这意味着您的子进程将循环并开始为更多的子进程创建自己的分支。

    • 在您的父进程分支中,您正在等待刚刚生成的子进程的响应,然后再继续创建下一个子进程。所以本质上你已经序列化了进程,不会利用多个进程。

    【讨论】:

    • 添加 _exit() 对我来说很有意义。至于第二个项目符号,我对 C 的理解还不够,无法看到不同的方法。不过,感谢您的帮助!
    • 一般来说:跟踪您在父进程中为子进程创建的所有管道。分叉并启动所有的孩子。将它们全部分叉后,从每个管道中读取它们的结果。
    • @saturn:或者如果你觉得很花哨,你可以使用系统调用select 来阻止,直到其中一个孩子有你的数据,然后从那个管道读取。这在这里可能并不重要,但是如果您开始编写网络代码或长时间运行的并行计算,它会有所帮助。
    猜你喜欢
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 2021-12-12
    • 1970-01-01
    • 2016-07-24
    • 2016-07-27
    • 2015-05-24
    相关资源
    最近更新 更多