C编程:Fork()和带管道的IPC

时间:2015-04-14 18:47:03

标签: c process pipe fork

所以我有这个问题,我需要创建3个进程(每个进程处理一个不同的任务)。第一个进程将信息发送到第二个进程(第一个进程等待第二个进程的确认)。然后第二个向第三个发送信息(第二个等待来自第三个的确认)。然后第三个处理最终信息......这个过程应该反复循环,直到过程一分析整个文本文件。到目前为止,我尝试用管道编写3个进程之间的通信。我不确定如何将流程2中的确认发送到流程1,将流程3发送到流程2.我也不完全确定如何循环它。谢谢!

我必须使用停止和等待协议......我不确定如何做到这一点。

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

int main(int argc, char *argv[]) {

    int c = 0, t = 0;

    int fd1[2], fd2[2];


    char *theFile = "/Users/Desktop/thefile";

    FILE *file = fopen (theFile, "r");

    if (file == NULL) {
        perror("FILE DOES NOT EXIST");
        exit(1);
    }

    while (c == 0) {

        int status;

        char readbuffer[80];
        char readbuffer2[80];
        int tTemp = 0;

        pipe(fd1);
        pipe(fd2);

        pid_t pid = fork();

        if (pid < 0) {
            perror("Pipe Error");
            exit(1);
        }

        if (pid == 0) {
            //Child 1
            close(fd1[0]);
            close(fd2[0]);
            close(fd2[1]);

            char line [80];
            int c2 = 0;
            file = fopen (theFile, "r");
            while (fgets(line, sizeof(line), file) != NULL){
                if (c2 == t) {
                    printf("Line: %s\n", line);
                    break;
                }
                c2++;
            }
            if (t != c2) {
                c = 1;
            } else {
                write(fd1[1], line, (strlen(line)+1));
            }

            t++;

            exit(1);
        }

        pid_t pid2 = fork();

        if (pid2 < 0) {
            perror("Pipe Error");
            exit(1);
        }

        if (pid2 == 0) {
            //Child 2
            close(fd1[1]);
            close(fd2[0]);
            read(fd1[0], readbuffer, sizeof(readbuffer));
            printf("2nd Child string: %s\n", readbuffer);
            char string2[80] = "asdfasdf";
            write(fd2[1], string2, (strlen(string2)+1));
            exit(1);
        }

        pid_t pid3 = fork();

        if (pid3 < 0) {
            perror("Pipe Error");
            exit(1);
        }

        if (pid3 == 0) {
            //Child 3
            close(fd2[1]);
            close(fd1[0]);
            close(fd1[1]);
            read(fd2[0], readbuffer2, sizeof(readbuffer2));
            exit(1);
        }


        waitpid(pid, &status, 0);

        waitpid(pid2, &status, 0);

        waitpid(pid3, &status, 0);


    }

    fclose(file);
    return 0;
}

1 个答案:

答案 0 :(得分:0)

当我通过评论了解问题时,您会询问两个不同的要求:

  1. 在每对进程之间实现“停止和等待”协议,
  2. 使用waitpid()收集完成的子进程
  3. 后者非常简单;你已经拥有的东西似乎很好。前者是你似乎最常被困住的东西。

    这里有几件事。一个是语义问题:停止&amp;等待,我们正在讨论它的形式,要求消息的接收者向发送者确认在发送者继续之前已成功接收消息。表征确认方式与将其表征为确认接收者执行任何特定操作的信号之间存在显着差异。接收者响应确认所做的是其自己的关注,而不是确认本身所固有的。

    至于通信,我建议在每对进程之间建立两个管道,一个用于每个方向的通信。等待确认,然后,进程只在适当的管道上执行阻塞读取。

    至于循环,每个进程必须单独循环,但循环将采用相同的形式:

    1. 阅读下一行(进程1从文件获取行;其他行从连接到前一进程的管道获取行)
    2. 如果没有可用的线路终止
    3. 除了进程1之外,在管道上写一个单字节确认消息到上一个进程
    4. 处理行
    5. 将该行写入相应的终点(进程3将行写入未指定的终点 - 可能是stdout - 其他行写入连接到下一个进程的管道的行)。
    6. 除了进程3之外,执行阻塞读取以接收来自下一进程的确认。
    7. 转到(1)
    8. 务必检查提供它们的所有功能的结果代码。由于这是大多数库函数和系统调用,它可能会变得乏味,所以我建议使用宏来帮助你。

      为了清晰和可读性,我建议将这三个过程中的每一个的工作都写成一个单独的功能。在fork()创建每个进程后,只需根据需要处理文件描述符修改并调用相应的函数。