“试着跑”;ls“grep r”;加上;execvp();

“试着跑”;ls“grep r”;加上;execvp();,c,C,我在两个子进程之间创建了一个管道, 首先,我运行ls,它会写入正确的fd, 然后,我运行grepr,它从正确的fd读取 我可以在终端中看到grep命令工作正常(输出) 问题是,grep没有退出,它仍然留在那里,即使ls不再运行 对于其他程序,管道工作正常 for (i = 0; i < commands_num ; i++) { //exec all the commands instants if (pcommands[i]._flag_pipe_out == 1) { //

我在两个子进程之间创建了一个
管道
, 首先,我运行
ls
,它会写入正确的fd, 然后,我运行
grepr
,它从正确的fd读取

  • 我可以在终端中看到
    grep
    命令工作正常(输出)

  • 问题是,
    grep
    没有退出,它仍然留在那里,即使
    ls
    不再运行

  • 对于其他程序,
    管道
    工作正常

    for (i = 0; i < commands_num ; i++) {   //exec all the commands instants
        if (pcommands[i]._flag_pipe_out == 1) { //creates pipe if necessary 
            if (pipe(pipe_fd) == -1) {
                perror("Error: \"pipe()\" failed");
            }
            pcommands[i]._fd_out = pipe_fd[1];
            pcommands[i+1]._fd_in = pipe_fd[0]; 
        }
        pid = fork();   //the child exec the commands  
        if (pid == -1) {
            perror("Error: \"fork()\" failed");
            break;          
        } else if (!pid) { //child process
    
            if (pcommands[i]._flag_pipe_in == 1) {  //if there was a pipe to this command
                if (dup2(pcommands[i]._fd_in, STDIN) == -1) {
                    perror("Error: \"dup2()\" failed");
                    exit(0);
                }
                close(pcommands[i]._fd_in);
            }
    
            if (pcommands[i]._flag_pipe_out == 1) { //if there was a pipe from this command
                if (dup2(pcommands[i]._fd_out, STDOUT) == -1) {
                    perror("Error: \"dup2()\" failed");
                    exit(0);
                }
                close(pcommands[i]._fd_out);
            } 
            execvp(pcommands[i]._commands[0] , pcommands[i]._commands); //run the command
    
            perror("Error: \"execvp()\" failed");
            exit(0);
        } else if (pid > 0) { //father process
        waitpid(pid, NULL, WUNTRACED);
        }
    }
    //closing all the open fd's
    for (i = 0; i < commands_num ; i++) {
        if (pcommands[i]._fd_in != STDIN) { //if there was an other stdin that is not 0
            close(pcommands[i]._fd_in);
        }           
        if (pcommands[i]._fd_out != STDOUT) { //if there was an other stdout that is not 1
            close(pcommands[i]._fd_out);            
        }   
    }
    
    现在,循环将执行两次(因为我有两个命令实例) 第一次,它将看到pcommands[0]的pipeout==1 创建管道 叉 pcommands[0]的管道输出==1 孩子:把2个复制到stdout 执行

    第二次: 不创建管道 叉 儿童: pcomands[1]的pipein==1 然后:将2复制到输入 埃克塞普

    此命令有效,我的输出为:

    errors.log exer2.pdf多路径尝试

    (所有带“r”的东西) 但随后它就卡住了,无法从
    grep
    中退出。。 在另一个终端中,我可以看到
    grep
    仍在工作

    我希望我关闭所有需要关闭的fd

    我不明白为什么它不工作,似乎我做得对(好吧,它适用于其他命令…)


    有人能帮忙吗?谢谢

    您没有关闭足够的管道文件描述符

    经验法则:
    • 如果使用
      dup()
      dup2()
      将管道文件描述符复制到标准输入或标准输出,则应关闭两个原始管道文件描述符
    您还需要确保,如果父shell创建管道,它将关闭管道文件描述符的两个副本

    还要注意,应该允许管道中的进程并发运行。特别是,管道的容量有限,当管道中没有空间时,流程会阻塞。限制可能非常小(POSIX要求它必须至少为4kib,但仅此而已)。如果您的程序处理兆字节的数据,则必须允许它们在管道中并发运行。因此,
    waitpid()
    应该出现在启动子循环的外部。您还需要在等待之前关闭父进程中的管道;否则,读取管道的子级将永远看不到EOF(因为理论上,父级可以写入管道,即使它不会)

    您有名称以下划线开头的结构成员。那很危险。以下划线开头的名称保留用于实现。C标准规定:

    ISO/IEC 9899:2011§7.1.3保留标识符

    -以下划线和大写字母或其他字母开头的所有标识符 下划线始终保留供任何使用。
    -所有以下划线开头的标识符始终保留用作标识符 文件范围在普通和标记名空间中

    这意味着,如果你遇到问题,那么问题是你的,而不是系统的。显然,您的代码是有效的,但是您应该意识到可能遇到的问题,避免这些问题是最明智的


    示例代码 这是基于上述代码的固定SSCCE:

    #include <assert.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    #include <unistd.h>
    
    typedef struct Command Command;
    struct Command
    {
        int _fd_out;
        int _fd_in;
        int _flag_pipe_in;
        int _flag_pipe_out;
        char **_commands;
    };
    
    typedef int Pipe[2];
    
    enum { STDIN = STDIN_FILENO, STDOUT = STDOUT_FILENO, STDERR = STDERR_FILENO };
    
    int main(void)
    {
        char *ls_cmd[] = { "ls", 0 };
        char *grep_cmd[] = { "grep", "r", 0 };
        Command commands[] =
        {
            {
                ._fd_in  = 0, ._flag_pipe_in  = 0,
                ._fd_out = 1, ._flag_pipe_out = 1,
                ._commands = ls_cmd,
            },
            {
                ._fd_in  = 0, ._flag_pipe_in  = 1,
                ._fd_out = 1, ._flag_pipe_out = 0,
                ._commands = grep_cmd,
            }
        };
        int commands_num = sizeof(commands) / sizeof(commands[0]);
    
        /* Allow valgrind to check memory */
        Command *pcommands = malloc(commands_num * sizeof(Command));
        for (int i = 0; i < commands_num; i++)
            pcommands[i] = commands[i];
    
        for (int i = 0; i < commands_num; i++) {   //exec all the commands instants
            if (pcommands[i]._flag_pipe_out == 1) { //creates pipe if necessary
                Pipe pipe_fd;
                if (pipe(pipe_fd) == -1) {
                    perror("Error: \"pipe()\" failed");
                }
                pcommands[i]._fd_out = pipe_fd[1];
                pcommands[i+1]._fd_in = pipe_fd[0];
            }
            pid_t pid = fork();   //the child exec the commands
            if (pid == -1) {
                perror("Error: \"fork()\" failed");
                break;
            } else if (!pid) { //child process
    
                if (pcommands[i]._flag_pipe_in == 1) {  //if there was a pipe to this command
                    assert(i > 0);
                    assert(pcommands[i-1]._flag_pipe_out == 1);
                    assert(pcommands[i-1]._fd_out > STDERR);
                    if (dup2(pcommands[i]._fd_in, STDIN) == -1) {
                        perror("Error: \"dup2()\" failed");
                        exit(0);
                    }
                    close(pcommands[i]._fd_in);
                    close(pcommands[i-1]._fd_out);
                }
    
                if (pcommands[i]._flag_pipe_out == 1) { //if there was a pipe from this command
                    assert(i < commands_num - 1);
                    assert(pcommands[i+1]._flag_pipe_in == 1);
                    assert(pcommands[i+1]._fd_in > STDERR);
                    if (dup2(pcommands[i]._fd_out, STDOUT) == -1) {
                        perror("Error: \"dup2()\" failed");
                        exit(0);
                    }
                    close(pcommands[i]._fd_out);
                    close(pcommands[i+1]._fd_in);
                }
                execvp(pcommands[i]._commands[0] , pcommands[i]._commands); //run the command
    
                perror("Error: \"execvp()\" failed");
                exit(1);
            }
            else
                printf("Child PID %d running\n", (int)pid);
        }
    
        //closing all the open pipe fd's
        for (int i = 0; i < commands_num; i++) {
            if (pcommands[i]._fd_in != STDIN) { //if there was another stdin that is not 0
                close(pcommands[i]._fd_in);
            }
            if (pcommands[i]._fd_out != STDOUT) { //if there was another stdout that is not 1
                close(pcommands[i]._fd_out);
            }
        }
    
        int status;
        pid_t corpse;
        while ((corpse = waitpid(-1, &status, 0)) > 0)
            printf("Child PID %d died with status 0x%.4X\n", (int)corpse, status);
    
        free(pcommands);
    
        return(0);
    }
    

    #包括。

    您需要接受过去的一些问题!这是什么意思?我该怎么做?在你过去的问题中,如果你认为答案是正确的,你需要通过点击答案有多少选票附近的绿色勾号来接受答案。如果人们看到你不接受任何答案,那么他们就不想回答你的问题。好吧,我不知道。。。我只是觉得我应该用上面的箭头来打分。。。谢谢谢谢,我明天就试试这个。我认为,通过快速阅读,问题在于我没有在叉子后关闭父亲的fd。。。(我以前试过,但出现了一些错误……我会再试一次)生活比这更复杂。在子进程中,您也必须关闭管道的两端,并且考虑到您组织数据结构的方式,这意味着如果子i-1的输入是管道,则子i必须查看其数据结构(关闭管道的输出端),如果其输出是管道,则子i+1必须查看其数据结构(关闭管道的输入端),这毫无疑问是混乱的。您还需要关闭主shell中的管道。我将您的代码反向工程为SSCCE().好的,谢谢,我还没有试过,我稍后再做…我只是想问一下SSCCE的问题是什么?你做了这个更改吗?还是想让我做?我不理解这部分,因为我没有看到代码的更改…我的机器上有可用的代码作为SSCCE;我还没有将其上传到这里(我有“坏”代码-可编译,但不像上面的片段那样工作;我也有“固定”代码-进行了必要的更改)。谢谢,它成功了!就我所知,你是如何做到的,这样它就不会变得“毫无争议的混乱”?我将感谢你的回答!
    #include <assert.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    #include <unistd.h>
    
    typedef struct Command Command;
    struct Command
    {
        int _fd_out;
        int _fd_in;
        int _flag_pipe_in;
        int _flag_pipe_out;
        char **_commands;
    };
    
    typedef int Pipe[2];
    
    enum { STDIN = STDIN_FILENO, STDOUT = STDOUT_FILENO, STDERR = STDERR_FILENO };
    
    int main(void)
    {
        char *ls_cmd[] = { "ls", 0 };
        char *grep_cmd[] = { "grep", "r", 0 };
        Command commands[] =
        {
            {
                ._fd_in  = 0, ._flag_pipe_in  = 0,
                ._fd_out = 1, ._flag_pipe_out = 1,
                ._commands = ls_cmd,
            },
            {
                ._fd_in  = 0, ._flag_pipe_in  = 1,
                ._fd_out = 1, ._flag_pipe_out = 0,
                ._commands = grep_cmd,
            }
        };
        int commands_num = sizeof(commands) / sizeof(commands[0]);
    
        /* Allow valgrind to check memory */
        Command *pcommands = malloc(commands_num * sizeof(Command));
        for (int i = 0; i < commands_num; i++)
            pcommands[i] = commands[i];
    
        for (int i = 0; i < commands_num; i++) {   //exec all the commands instants
            if (pcommands[i]._flag_pipe_out == 1) { //creates pipe if necessary
                Pipe pipe_fd;
                if (pipe(pipe_fd) == -1) {
                    perror("Error: \"pipe()\" failed");
                }
                pcommands[i]._fd_out = pipe_fd[1];
                pcommands[i+1]._fd_in = pipe_fd[0];
            }
            pid_t pid = fork();   //the child exec the commands
            if (pid == -1) {
                perror("Error: \"fork()\" failed");
                break;
            } else if (!pid) { //child process
    
                if (pcommands[i]._flag_pipe_in == 1) {  //if there was a pipe to this command
                    assert(i > 0);
                    assert(pcommands[i-1]._flag_pipe_out == 1);
                    assert(pcommands[i-1]._fd_out > STDERR);
                    if (dup2(pcommands[i]._fd_in, STDIN) == -1) {
                        perror("Error: \"dup2()\" failed");
                        exit(0);
                    }
                    close(pcommands[i]._fd_in);
                    close(pcommands[i-1]._fd_out);
                }
    
                if (pcommands[i]._flag_pipe_out == 1) { //if there was a pipe from this command
                    assert(i < commands_num - 1);
                    assert(pcommands[i+1]._flag_pipe_in == 1);
                    assert(pcommands[i+1]._fd_in > STDERR);
                    if (dup2(pcommands[i]._fd_out, STDOUT) == -1) {
                        perror("Error: \"dup2()\" failed");
                        exit(0);
                    }
                    close(pcommands[i]._fd_out);
                    close(pcommands[i+1]._fd_in);
                }
                execvp(pcommands[i]._commands[0] , pcommands[i]._commands); //run the command
    
                perror("Error: \"execvp()\" failed");
                exit(1);
            }
            else
                printf("Child PID %d running\n", (int)pid);
        }
    
        //closing all the open pipe fd's
        for (int i = 0; i < commands_num; i++) {
            if (pcommands[i]._fd_in != STDIN) { //if there was another stdin that is not 0
                close(pcommands[i]._fd_in);
            }
            if (pcommands[i]._fd_out != STDOUT) { //if there was another stdout that is not 1
                close(pcommands[i]._fd_out);
            }
        }
    
        int status;
        pid_t corpse;
        while ((corpse = waitpid(-1, &status, 0)) > 0)
            printf("Child PID %d died with status 0x%.4X\n", (int)corpse, status);
    
        free(pcommands);
    
        return(0);
    }