ubuntu 为什么我的C程序的管道有两个管道挂起?

cngwdvgl  于 12个月前  发布在  其他
关注(0)|答案(3)|浏览(206)

我正在尝试写一个C程序,它可以执行类似于管道ls | wc | wc的操作。我已经为ls | wc执行过了,它运行得很好,但我不知道为什么我的程序会停在指定行的子进程上。

int main (void)
{
    pid_t pid_fils, pid_pfils;

    int fd[2], fd2[2];

    if(pipe(fd)==-1 || pipe(fd2)==-1)
    {
        printf("pipe failed!");
        return 1;
    }

    printf("program started\n");
    pid_fils=fork();
    if(pid_fils==0)
    {
        pid_pfils=fork();
        if(pid_pfils==0)
        {
            //action3
            printf("I am the grandson\n");
            close(fd[0]);//close read side
            dup2(fd[1],1);//connect write with stdout
            close(fd[1]);//close write side
            execlp("ls","ls",(char*)0);
            //execvp("ls",argv3);
            return 0;/*actions grandson*/
        }
        else
        {
            //action2
            printf("I am the son\n");
            wait();
            printf("son, wait ok\n");
            >close(fd[1]);  //close read side
            >dup2(fd[0],0); //connect write with stdin
            >close(fd[0]);  //close read side
            
            ///////pipe2////
           > close(fd2[0]);  //close read side
            >dup2(fd2[1],1); //connect write with stdout/*it stops here -can't display "ok!"*/
            printf("ok!\n");    
            >close(fd2[1]);  //close write side

            execlp("wc","wc",(char*)0);
            printf("error exec returned!\n");    
            return 0;
        }
    }
    else
    {
        ///action1
        printf("I am the parent\n");
        wait();
        printf("parent,wait ok\n");
        close(fd2[1]);  //close write side, 
        dup2(fd2[0],0); //connect read with stdin
        close(fd2[0]);  //close read side
        execlp("wc","wc",(char*)0);
        return 0;/*the parent*/
    }
    return 1;
}

字符串

uhry853o

uhry853o1#

确保关闭所有未使用的描述符。在您的情况下,最简单的解决方案是将管道(fd)的创建移动到第一个if块(在第一个子进程中)。问题是,只要任何进程都可能写入管道,读取器就不会被删除,因此不会终止。

if(pipe(fd2)==-1)
{
    printf("pipe failed!");
    return 1;
}

printf("program started\n");
pid_fils=fork();
if(pid_fils==0)
{
    if(pipe(fd)==-1)
    {
        printf("pipe failed!");
        return 1;
    }
    pid_pfils=fork();

字符串
我还应该提一下,你可能需要重新考虑等待调用。不确定你打算用它们做什么,但你不希望“ls”进程在输出时阻塞,因为阅读器还没有启动。

wbrvyc0a

wbrvyc0a2#

dup2(fd2[1],1);

字符串
上面一行将首先关闭描述符1处的文件,然后将描述符从fd2[1]复制到1。
1是stdout。意味着调用关闭了stdout。
printf打印到stdout,这意味着printf打印到1,它现在被分配给管道fd2
所以你的OK进入了管道而不是在屏幕上。
尝试

//action2
        printf("I am the son\n");
        wait();
        printf("son, wait ok\n");
        close(fd[1]);  //close read side
        dup2(fd[0],0); //connect write with stdin
        close(fd[0]);  //close read side

        ///////pipe2////
        int my_terminal_out = dup(1);
        close(fd2[0]);  //close read side
        dup2(fd2[1],1); //connect write with stdout/*it stops here -can't display "ok!"*/
        fprintf(my_terminal_out, "ok!\n");    
        close(fd2[1]);  //close write side


还没有测试。你应该测试你的代码的其余部分是否有类似的错误。
”DrC说。

mf98qq94

mf98qq943#

扩展这个SO answer,我们可以创建一个额外的管道,fork另一个进程,并相应地连接管道。

// two-pipes.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

// C implementation for the `ls -la | wc | wc` pipeline.
int main(int argc, char *argv[]) {
    // We declare two pipes, one for each pair of processes, i.e.,
    // ls -al pipefd1 wc pipefd2 wc
    int pipefd1[2];
    int pipefd2[2];
    pid_t ls_pid, wc_pid1, wc_pid2;

    pipe(pipefd1);
    pipe(pipefd2);

    // CHILD PROCESS: ls
    if ((ls_pid = fork()) == 0) {
        // We close-and-then-connect STDOUT to pipefd1's write end so the
        // process write to the pipe instead of the screen.
        dup2(pipefd1[1], STDOUT_FILENO);

        // Since STDOUT_FILENO also refers to pipefd's write end, we can
        // close this file descriptor; it's no longer needed.
        close(pipefd1[1]);

        // The process doesn't use these file descriptors so we close them.
        close(pipefd1[0]);
        close(pipefd2[0]);
        close(pipefd2[1]);

        // Execute the `ls` command, and exit if errors out.
        if ((execl("/bin/ls", "ls", "-al", (char *) NULL)) < 0) exit(0);
    }
    else if (ls_pid < 0) {
        fprintf(stderr, "failed to fork ls process");
        exit(0);
    }

    // CHILD PROCESS: wc (1)
    if ((wc_pid1 = fork()) == 0) {
        // We close-and-then-connect STDIN and STDOUT to pipefd1's read and
        // and pipefd2's write end so the process read from pipefd1 and write
        // to pipefd2 instead of from the keyboard and to the screen respectively.
        dup2(pipefd1[0], STDIN_FILENO);
        dup2(pipefd2[1], STDOUT_FILENO);

        // Since STDIN_FILENO and STDOUT_FILENO also refer to pipefd1's read
        // end and pipefd2's write end respectively, we can close these file
        // descriptors.
        close(pipefd1[0]);
        close(pipefd2[1]);

        // The process doesn't use these file descriptors so we close them.
        close(pipefd1[1]);
        close(pipefd2[0]);

        // Execute the `wc` command, and exit if errors out.
        if ((execl("/usr/bin/wc", "wc", (char *) NULL)) < 0) exit(0);
    }
    else if (wc_pid1 < 0) {
        fprintf(stderr, "failed to fork wc process");
        exit(0);
    }

    // CHILD PROCESS: wc (2)
    if ((wc_pid2 = fork()) == 0) {
        // We close-and-then-connect STDIN to pipefd2's read end so the process
        // read from the pipe instead of from the keyboard.
        dup2(pipefd2[0], STDIN_FILENO);

        // Since STDIN_FILENO also refers to the pipefd2's read end, we can
        // close this file descriptor; it's no longer needed.
        close(pipefd2[0]);

        // The process doesn't use these file descriptors so we close them.
        close(pipefd1[0]);
        close(pipefd1[1]);
        close(pipefd2[1]);

        // Execute the `wc` command, and exit if errors out.
        if ((execl("/usr/bin/wc", "wc", (char *) NULL)) < 0) exit(0);
    }
    else if (wc_pid1 < 0) {
        fprintf(stderr, "failed to fork wc process");
        exit(0);
    }
    
    // PARENT PROCESS

    // The parent process isn't using the pipes, however these descriptors are
    // another references to the pipe's read and write ends and we must close
    // them. Otherwise, it doesn't send the EOF so the children can continue
    // (children block until all input has been processed).
    close(pipefd1[0]);
    close(pipefd1[1]);
    close(pipefd2[0]);
    close(pipefd2[1]);

    // The parent process waits for the three child processes to finish before
    // exiting.
    int ls_status, wc_status1, wc_status2;
    pid_t ls_wpid = waitpid(ls_pid, &ls_status, 0);
    pid_t wc_wpid1 = waitpid(wc_pid1, &wc_status1, 0);
    pid_t wc_wpid2 = waitpid(wc_pid2, &wc_status2, 0);

    // Return main's status based on whether the parent process waited both
    // child processes successfully. Status based only on `ls_status`.
    return
        ls_pid == ls_wpid && WIFEXITED(ls_status) &&
        wc_pid1 == wc_wpid1 && WIFEXITED(wc_status1) &&
        wc_pid2 == wc_wpid2 && WIFEXITED(wc_status2)
        ? WEXITSTATUS(ls_status)
        : -1;
}

字符串
编译并运行它:

$ ls -la
total 112
drwxr-xr-x   8     256 Nov 20 13:52 .
drwxr-x---+ 91    2912 Nov 20 13:55 ..
-rwxr-xr-x   1   33896 Nov 20 13:48 a.out
-rw-r--r--   1      45 Nov 17 15:33 error.log
-rw-r--r--@  1    2390 Nov 20 09:51 ls-wc-pipes.c
-rw-r--r--   1     116 Nov 17 16:01 out.log
-rw-r--r--@  1    2647 Nov 20 09:49 so-pipes.c
-rw-r--r--@  1    4021 Nov 20 13:52 two-pipes.c
$ gcc two-pipes.c && ./a.out
       1       3      25

相关问题