通过“fork”为一个父进程创建多个进程

时间:2016-11-21 23:12:04

标签: c pipe

我想创建一个小程序,接受来自stdin的用户输入,以获得他们想要的进程数,然后,我的程序将按用户指定的方式分叉n个进程。稍后,我想将子数据传输给父级。

但是,我只想要一个父进程。我一直试图弄清楚这个算法,也许我过于复杂了,但我被卡住了。

请注意我只能使用C中的fork和pipe功能(所以不要太疯狂!)

这是我的算法。

仅当我是父进程时才循环,如果我是子进程,则不循环。

如果我是进入循环的父进程,那么我将调用fork()。否则,我还是个孩子,我会做一些与孩子有关的任务(之后我可能会将这些任务交给父母)。孩子不应该重新进入循环,以避免创建子女进程。

这有意义吗?

你建议我做什么?

2 个答案:

答案 0 :(得分:1)

让我们说n是您输入的孩子数量。如果你为每个孩子使用一个烟斗,让我们看看你能做些什么。

在父流程中:

pid_t pid;
int fd[n][2];
for(i = 0; i < n; i++) {
    pipe(fd[i]);
    pid = fork();
    if (pid < 0) {
        perror("whatever");
        exit(1);
    }
    else if (pid == 0) {
        for(j = 0; j < i; j++) {
            if (close(fd[j][0]) < 0) {
                perror("closing fd[0]");
                exit(1);
            }
            if (close(fd[j][1]) < 0) {
                perror("closing fd[1]");
                exit(1);
            }
        }
        func(fd[i]);
    }
}
// other parent stuff next && close file discriptors not needed

你的func()应该是孩子们必须做的事情。它将子管道的2个文件描述符作为参数。请注意,在func的末尾,您应该exit()

为每个孩子制作一个管道的解决方案会好一点但比这更复杂一点(提示:你可以传递fd&#39; s作为参数,也要小心关闭所有fd!)< / p>

此外,您可以通过定义pid而不是pid_t pid[n];来保留每个孩子的pid,并将每个pid称为pid[i]

不要忘记等待每个孩子死!

答案 1 :(得分:0)

如果是我,我会将所有fork()pipe()内容移动到它自己的子程序中,并使用明确的语义,并从main()中的循环中调用该子程序。 / p>

在下面的示例中,spawn() forks调用child中的work函数,确保子项正确退出,并在父项中返回。

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


/* Launch a child. This routine exit()s in the child and
 * return()s in the parent */
void spawn(void (*fn)(int), int *fd) {
    int pipefd[2];
    int pid;

    if(pipe(pipefd) < 0) {
        perror("pipe");
        exit(1);
    }
    switch(pid = fork()) {
    case -1:  /* Error */
        perror("fork");
        exit(1);
        break;
    case 0:   /* Child */
        close(pipefd[0]); /* Kids only talk */
        fn(pipefd[1]);    /* Put the kid to work */
        exit(0);           /* Kill the kid */
        break;
    default:  /* Parent */
        close(pipefd[1]); /* Parents only listen */
        *fd = pipefd[0];
        printf("Spawning PID=%d, FD=%d\n", pid, *fd);
        break;
    }
}

int
get_number_of_children() {
    /* TODO: Do stdin-reading here and return a good number */
    return 3;
}

void do_work(int fd) {
    /* TODO: Whatever work the children might do */
    /* For example: */
    write(fd, "hello", 5);
}

int main (int ac, char **av) {
    int nkids = get_number_of_children();
    int fd_array[nkids];
    int pid;

    /* Birth the children */
    for(int i = 0; i < nkids; i++) {
        spawn(do_work, &fd_array[i]);
    }

    /* TODO: Read the data from the file descriptors in fd_array */

    /* Finally, wait for all children to die */
    while((pid = wait(0)) != -1) {
        printf("Waited PID=%d\n", pid);
    }
}