代码之家  ›  专栏  ›  技术社区  ›  Pedro

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

  •  2
  • Pedro  · 技术社区  · 6 年前

    我一直在尝试编写一个非常简单的程序,其中父进程通过管道将100行传递给子进程。然后,子级应该使用生成的行并执行命令行程序 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;
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   melpomene    6 年前

    我很小心地关闭了两个进程都没有使用的所有描述符

    不是真的。

    dup2(fd[1], STDOUT_FILENO);
    

    这是你做的 stdout 副本 fd[1]

    close(fd[1]);
    

    在这里,您可以关闭 fd【1】 但是 标准装置 仍然打开。

    那你呢 fork 。此时,两个进程都可以通过 标准装置

        dup2(fd[0], STDIN_FILENO);
        close(fd[0]);
    

    在复制的子进程中 fd[0] stdin 并关闭 fd[0]

    然后,当你执行 more ,它仍然可以访问管道的两端(通过 标准DIN / 标准装置 )。

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

    实际上,你什么都没关。

    还有第二个问题:父进程写入 标准装置 ,它绑定到管道的写入端,没有任何人阅读它。取决于你写了多少 标准装置 是行缓冲还是块缓冲 标准装置 缓冲区是,以及管道本身可以存储多少,这本身可能会导致死锁。如果管道已满,周围没有人阅读, 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;
    }
    
    推荐文章