execlp() 无法检索正确的输入

execlp() failing to retrieve correct input

我一直在尝试编写一个非常简单的程序,其中 parent 进程通过管道将 100 行代码传递给 child 进程。 child 然后应该使用生成的行并在这些行上执行命令行程序 more。 但是,当我尝试 运行 程序时,它就死机了。我很小心地关闭了所有未被两个进程使用的描述符,但我真的不明白是什么导致了它。

代码:

int main(void){

    int fd[2];
    if (pipe(fd) == -1){
        perror("Error creating pipe");
        return 1;
    }

    dup2(fd[1], STDOUT_FILENO);

    int i;
    for (i = 1; i <= 100; i++){
        printf("Line %d\n", i);
    }
    close(fd[1]);

    pid_t pid = fork();
    if(pid == 0) {
        dup2(fd[0], STDIN_FILENO);
        close(fd[0]);

        execlp("more", "more",(char*) NULL);
        fprintf(stderr, "Failed to execute 'more'\n");
        exit(1);
    }
    wait(NULL);
    return 0;
}

I was careful to close all descriptors not being used by both processes

不是真的。

dup2(fd[1], STDOUT_FILENO);

这里你制作stdout一份fd[1]

close(fd[1]);

您在这里关闭 fd[1],但 stdout 仍处于打开状态。

那你fork。此时两个进程都可以通过 stdout.

访问管道的写端
    dup2(fd[0], STDIN_FILENO);
    close(fd[0]);

在子进程中,您将 fd[0] 复制到 stdin 并关闭 fd[0]

然后,当您执行 more 时,它仍然可以访问管道的两端(通过 stdin / stdout)。

同时您的父进程可以访问管道的两端(通过 fd[0] / stdout)。

实际上你什么都没关闭。

还有第二个问题:您的父进程写入 stdout,它绑定到管道的写入端,没有任何人读取它。根据您写入的量,stdout 是行缓冲还是块缓冲,stdout 缓冲区有多大,以及您的管道本身可以存储多少,这本身可能会死锁。如果管道满了并且周围没有人读取它,printf 就会阻塞。


要解决此问题,请不要在父进程中 dup2 并且在子进程启动之前不要写入管道。

int main(void){
    int fd[2];
    if (pipe(fd) == -1){
        perror("Error creating pipe");
        return 1;
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("Error spawning process");
        return 2;
    }

    if (pid == 0) {
        close(fd[1]);  /* close write end of the pipe in the child */
        dup2(fd[0], STDIN_FILENO);
        close(fd[0]);

        execlp("more", "more", (char*)NULL);

        fprintf(stderr, "Failed to execute 'more'\n");
        exit(1);
    }

    close(fd[0]);  /* close read end of the pipe in the parent */

    FILE *fp = fdopen(fd[1], "w");
    if (!fp) {
        perror("Error opening file handle");
        return 3;
    }

    for (int i = 1; i <= 100; i++){
        fprintf(fp, "Line %d\n", i);
    }
    fclose(fp);  /* flush and close write end of the pipe in the parent */

    wait(NULL);
    return 0;
}