管道问题c

时间:2015-08-15 19:37:33

标签: c pipe

我遇到管道问题。我试图执行例如ls | grep测试和我的程序冻结。我的程序是一个shell程序,我得到重定向和其他工作,但我不能让管道工作......我做错了什么?我已经找到答案,但无法找到解决问题的方法。

if(pipe(fd_pipe) < 0)
        perror("pipe error...");

    if ((pid = fork()) < 0) /* fork a child process */
    {     
        perror("ERROR: forking child process failed\n");
        exit(1);
    }
    else if (pid == 0) /* the child process, do the first command */
    {  
        printf("In first child...\n");
        //dupPipe(fd_pipe, 1, STDOUT_FILENO);   /* send to write end of pipe */

        fflush(stdout);
        std_out = dup(1); // for later restore...
        close(fd_pipe[0]);
        dup2(fd_pipe[1], 1);


        printf("exec %s in first child...\n", comline[0].argv[0]);         
        if (execvp(comline[0].argv[0], comline[0].argv) < 0) /* execute the command  */
        {
            fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]);
            fflush(stderr);
            perror("");
        }

    }
    else    /* parent process*/
    {
        while (wait(&status) != pid)    //wait for child to completion
            ;

        fflush(stdin);
        std_in = dup(0); // for later restore...
        close(fd_pipe[1]);
        dup2(fd_pipe[0], 0);


        if (execvp(comline[1].argv[0], comline[1].argv) < 0) /* execute the command  */
            {
                fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]);
                fflush(stderr);
                perror("");
            }

2 个答案:

答案 0 :(得分:0)

当第一个子进程仍在运行时,您正在调用wait()。这意味着没有任何内容可以读取第一个孩子写入stdout的内容 - 如果管道填满,第一个子进程将阻止写入stdout。但是,由于父进程为第一个孩子结束wait(),所以最终会陷入僵局。

答案 1 :(得分:0)

请注意,Andrew Henleanswer中的注释长期适用 - 您需要同时运行管道中的所有程序,以确保没有任何死锁,因为一个进程是尝试写入一个完整的管道而另一个正在等待一个进程完成,然后再执行从管道读取的代码(或程序)。直接在该问题下提出的意见也适用。

但是,这个代码是从你的代码中获得的,带有最小的band-aiding(我确实注释掉了未使用的变量std_instd_out),编译干净并运行并产生合理的输出。

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

struct cmd
{
    char **argv;
};

int main(void)
{
    int fd_pipe[2];
    int pid;
    //int std_in;
    //int std_out;
    int status;
    char *cmd1[] = { "ls", 0 };
    char *cmd2[] = { "grep", "test", 0 };
    struct cmd comline[2] = { { cmd1 }, { cmd2 } };

    if(pipe(fd_pipe) < 0)
        perror("pipe error...");

    if ((pid = fork()) < 0) /* fork a child process */
    {     
        perror("ERROR: forking child process failed\n");
        exit(1);
    }
    else if (pid == 0) /* the child process, do the first command */
    {  
        printf("In first child...\n");
        //dupPipe(fd_pipe, 1, STDOUT_FILENO);   /* send to write end of pipe */

        fflush(stdout);
        //std_out = dup(1); // for later restore...
        close(fd_pipe[0]);
        dup2(fd_pipe[1], 1);

        printf("exec %s in first child...\n", comline[0].argv[0]);         
        if (execvp(comline[0].argv[0], comline[0].argv) < 0) /* execute the command  */
        {
            fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]);
            fflush(stderr);
            perror("");
        }
        exit(EXIT_FAILURE);

    }
    else    /* parent process*/
    {
        while (wait(&status) != pid)    //wait for child to completion
            ;

        fflush(stdin);
        //std_in = dup(0); // for later restore...
        close(fd_pipe[1]);
        dup2(fd_pipe[0], 0);

        if (execvp(comline[1].argv[0], comline[1].argv) < 0) /* execute the command  */
        {
            fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]);
            fflush(stderr);
            perror("");
        }
        exit(EXIT_FAILURE);
    }
    printf("Exiting from %d\n", (int)getpid());
    return 0;
}

在一个包含130多个文件的目录中(从ls得到大约1.5 KiB的输出),我得到:

$ ./p97
In first child...
chk-utf8-test.sh
chk-wchar-test.sh
pbb-test.data
test-fstatat.c
test-rename.c
utf8-test.c
wchar-test.c
$

这是我从诊断消息中(当然)运行ls | grep test的命令行获得的。

但是,我怀疑你没有向我们展示所有的代码。 std_instd_out变量让我怀疑实际上还有一些其他代码,并且可能在父进程中发生pipe()操作然后分叉,然后子进程运行问题中显示的其余代码。如果存在这样的情况,则可能存在命令未完成的问题,因为管道未正确关闭。