【问题标题】:read system call returns -1 when reading from pipe in child process从子进程中的管道读取时,读取系统调用返回 -1
【发布时间】:2019-04-10 10:03:08
【问题描述】:

为了了解 Pipe IPC 机制的工作原理,我编写了一个简单的程序,该程序创建了两个使用管道共享数据的子进程。第一个子进程必须从文件中读取数据并将其传递给管道。

之后,第二个子进程必须读取它,将其转换为大写并将其写入另一个文件。从管道读取时,第二个子进程中的 read 系统调用返回 -1。此外,当我执行程序时,在某些情况下,第一个孩子的 printf 不会打印任何内容,而在其他情况下,第二个孩子的 printf 也不会打印。您能否指出导致问题的程序中的错误?

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

    int fd[2];

    long length;
    char buff1[250];
    char buff2[250];

    FILE * fptr1;
    FILE * fptr2;

    pid_t A, B;
    pipe(fd);

    A = fork();

    if (A == -1) {
        printf("error in fork of A\n");
        exit(1);
    }
    if (A == 0) {
        fptr1 = fopen(argv[1], "r"); // program receives file names as argument

        if (fptr1 == NULL) {
            printf("Erro in file open1\n");
            exit(1);
        }

        fseek(fptr1, 0 L, SEEK_END);
        length = ftell(fptr1);
        fseek(fptr1, 0 L, SEEK_SET);

        close(fd[0]);

        fread(buff1, length, 1, fptr1);
        buff1[length] = '\0';
        printf("buff1 = %s", buff1);
        write(fd[1], buff1, length);

        fclose(fptr1);
        exit(0);
    } else {
        B = fork();
        if (B == -1) {
            printf("Error in forking child B");
            exit(1);
        }
        if (B == 0) {
            fptr2 = fopen(argv[2], "w");

            if (fptr2 == NULL) {
                printf("Error in file open2\n");
                exit(1);
            }

            close(fd[1]);
            int n = read(fd[0], buff2, length);
            printf("n = %d\n", n);
            upper_string(buff2); // converts characters to uppecase
            fwrite(buff2, 1, length, fptr2);
            fclose(fptr2);
        }
    }
    return 0;
}

【问题讨论】:

  • 看来length 在第二个孩子中是未定义的,因为它没有在任何地方设置。未定义的行为,如果幸运的话可能为零,因此不会从管道中读取任何内容。
  • 如果将父代码路径和子代码路径(fork 之后)拆分为不同的函数,则避免此类问题要容易得多。拥有一个在顶部声明局部变量但仅在某些代码路径上初始化的大函数总是很麻烦。
  • 哦,如果read 返回-1,你真的应该尝试打印errno
  • 为第二个孩子设置 length 解决了未定义的行为。我还在父进程中添加了两个对wait() 的调用,这样现在程序就不会挂起。

标签: c


【解决方案1】:

这里有几件事情需要考虑。我想指出的第一件事是您不需要使用两个 fork() 调用。在这种情况下,您有三个并行工作的进程(父进程和两个子进程,每个 fork() 调用一个)。

在处理并行工作的进程时要考虑的一个重要点是同步性。在您的代码中,您正在创建两个进程。父进程不等待它的任何子进程,所以它完成了它的执行,如果子进程还没有完成,它们将成为 init 进程的子进程。但除此之外,您还有典型的生产者消费者问题。您的一个孩子生产一些东西,另一个消费它,但是他们如何并行工作,消费者需要知道该产品已准备好被消费。所以,在这种情况下,我认为完成这项工作的最简单方法是只使用一个 fork(),因此子进程成为生产者,父进程(消费者)等到其子进程完成工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-03
    • 2016-02-06
    • 1970-01-01
    • 2020-09-14
    • 2021-10-13
    • 1970-01-01
    • 2013-07-12
    • 1970-01-01
    相关资源
    最近更新 更多