使用fork()和管道的进程环

时间:2014-04-01 17:02:19

标签: c linux process pipe

我在一小时内就这个问题一直在震撼我的大脑。我必须用n个进程创建一个进程环(数量通过cmd作为参数传递)。父进程将他的PID发送给他的第一个孩子,这个将父亲的PID和他自己的PID发送给他的下一个兄弟,直到我们创建了n个孩子。之后,父进程将获得他所有孩子的PID。

假设父进程'PID为3400,我们创建了两个子进程,因此环由三个进程组成

3400 + 3401(第一个孩子的PID)+ 3402(第二个孩子的PID)= 10203

父进程应该得到10203。

我想过一个“for”循环,其中子进程只使用一个管道从兄弟到兄弟发送兄弟PID的添加。尽管如此,我还没有找到解决方案。

3 个答案:

答案 0 :(得分:2)

鉴于任务是使用fork()pipe(),您可能需要使用以下算法:

  • Parent为其创建管道以写入1 st child。
  • Parent将管道的写入结束打开到1 st child。
  • Parent从N th 子节点打开管道的读取端。
  • 对于每个孩子n = 1..N,Parent为n th 子项创建输出管道以与n + 1 th 对话。
  • 父母要求 th 孩子。
  • n th 子句关闭其输入管道的写入端和输出管道的读取端。
  • n th 子节点从输入管道中读取PID的总和,将其自己的pid添加到总和中,然后将其写入输出管道,然后退出。
  • 同时,Parent将输入管道的两端关闭到n th (除了必须保持打开的描述符除外),然后循环返回以创建n + 1 th 孩子的管子然后是孩子。
  • 当所有子项都已启动时,父项将其PID写入1 st 子项并关闭该管道的写入结束。
  • 然后它从N th 子节点读取响应,关闭管道的读取端,并打印结果。

除非每个孩子也将其PID写入标准输出,或者父母(知道所有子PID)计算验证它的答案,否则验证总和的方法不太明显。


由于完全没有错误检查而没有标记:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int N = (argc > 1) ? atoi(argv[1]) : 10;
    int c1_wr;
    int cN_rd;
    int p1[2];
    int p2[2];
    int pid_chk = getpid();

    if (N <= 0 || N >= 100)
        N = 10;

    pipe(p1);
    c1_wr = dup(p1[1]);
    printf("%d children\n", N);
    printf("Parent   = %d\n", pid_chk);

    for (int n = 0; n < N; n++)
    {
        int pid;
        pipe(p2);
        fflush(stdout);
        if ((pid = fork()) == 0)
        {
            close(p1[1]);
            close(p2[0]);
            int pid_sum;
            read(p1[0], &pid_sum, sizeof(pid_sum));
            pid_sum += getpid();
            write(p2[1], &pid_sum, sizeof(pid_sum));
            close(p1[0]);
            close(p2[1]);
            exit(0);
        }
        printf("Child %2d = %d\n", n+1, pid);
        pid_chk += pid;
        close(p1[0]);
        close(p1[1]);
        p1[0] = p2[0];
        p1[1] = p2[1];
    }

    cN_rd = p2[0];
    close(p2[1]);

    int pid_sum = getpid();
    write(c1_wr, &pid_sum, sizeof(pid_sum));
    close(c1_wr);
    read(cN_rd, &pid_sum, sizeof(pid_sum));
    close(cN_rd);
    printf("PID sum = %d\n", pid_sum);
    printf("PID chk = %d\n", pid_chk);

    return 0;
}

示例运行:

10 children
Parent   = 49686
Child  1 = 49688
Child  2 = 49689
Child  3 = 49690
Child  4 = 49691
Child  5 = 49692
Child  6 = 49693
Child  7 = 49694
Child  8 = 49695
Child  9 = 49696
Child 10 = 49697
PID sum = 546611
PID chk = 546611

如果(a)省略它并且(b)通过管道运行输出,则fflush(stdout);的目的变得清晰。这是必要的。

答案 1 :(得分:0)

您需要某种进程间通信(IPC)。常用的IPC方法有:

  • loopback socket

  • 共享内存

您可以在wikipedia IPC article中找到所有其他方法。

答案 2 :(得分:0)

如果您控制子进程的行为,并且父进程在启动子进程之前没有重要/难以重新创建的状态,则可以简化操作。

您可以让父级递归启动已分离的子项,终止自身,让最后一个子项重新启动父项,而不是IPC;

  1. 调用parent n,其中n是要生成的子项数。
  2. parent
    • 调用child arg1-1 0并终止,
    • 如果使用"0"调用arg1,它会将自己的PID添加到arg2并且您已完成,即使在进程树方面它不是真正的“父”什么。
  3. child
    • 调用child arg-1 arg2+pid,其中pid是孩子自己的PID。
    • 如果"0"调用了arg1,则会调用parent 0 arg2+pid