ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

学习管道,exec,fork,并尝试将三个流程链接在一起

2019-10-13 12:00:29  阅读:220  来源: 互联网

标签:c-3 linux fork pipe exec


我正在学习使用管道,并在pipes上跟随此代码.该程序使用fork创建两个子进程.第一个孩子运行“ ls”命令并输出到pipe1.从pipe1进行的第二次读取运行’wc’并输出到stdout.

我只是想在中间添加第三个进程,该进程从pipe1读取并输出到pipe2.基本上我想做的是

  ls | cat | wc -l

我正在尝试做的是:

(ls)stdout -> pipe1 -> stdin(cat)stdout-> stdin(wc -l) -> stdout

什么都不会打印到stdout,程序也永远不会退出.

这是我的代码,其中包含进程#3的更改

int
main(int argc, char *argv[])
{
    int pfd[2];                                     /* Pipe file descriptors */
    int pfd2[2];

    if (pipe(pfd) == -1)                            /* Create pipe */
        perror("pipe");

    if (pipe(pfd2) == -1)                            /* Create pipe */
        perror("pipe");

    /*
    Fork process 1 and exec ls command
    write to pfd[1], close pfd[0]
    */
    switch (fork()) {
    case -1:
        perror("fork");

    case 0:             
        if (close(pfd[0]) == -1)                   
            perror("close 1");

        // dup stdout on pfd[1]
        if (pfd[1] != STDOUT_FILENO) {            
            if (dup2(pfd[1], STDOUT_FILENO) == -1)
                perror("dup2 2");
            if (close(pfd[1]) == -1)
                perror("close 4");
        }
        execlp("ls", "ls", (char *) NULL);          
        perror("execlp ls");
    default:            
        break;
    }

    /*
    *   Fork process 2 and exec wc command
    read from pfd[0], close pfd[1]
    write to pfd[1], close pfd2[0]
    */
    switch (fork()) {
    case -1:
        perror("fork");
    case 0:  
        // read from pfd[0]           
        if (close(pfd[1]) == -1)                  
            perror("close 3");

        if (pfd[0] != STDIN_FILENO) {            
            if (dup2(pfd[0], STDIN_FILENO) == -1)
                perror("dup2 2");
            if (close(pfd[0]) == -1)
                perror("close 4");
        }

        if (pfd2[1] != STDOUT_FILENO) {            
            if (dup2(pfd2[1], STDOUT_FILENO) == -1)
                perror("dup2 2");
            if (close(pfd2[1]) == -1)
                perror("close 4");
        }

        execlp("cat", "cat", (char *) NULL);
        perror("execlp cat");
    default:
        break;
    }

    /*
    *   Fork process 3
    */
    switch (fork()) {
    case -1:
        perror("fork");
    case 0:          
        if (close(pfd2[1]) == -1)                  
            perror("close 3");

        if (pfd2[0] != STDIN_FILENO) {            
            if (dup2(pfd2[0], STDIN_FILENO) == -1)
                perror("dup2 2");
            if (close(pfd2[0]) == -1)
                perror("close 4");
        }

        execlp("wc", "wc", "-l", (char *) NULL);
        perror("execlp wc");
    default:
        break;
    }


    /* Parent closes unused file descriptors for pipe, and waits for children */

    if (close(pfd[0]) == -1)
        perror("close 5");
    if (close(pfd[1]) == -1)
        perror("close 6");
    if (close(pfd2[0]) == -1)
        perror("close 5");
    if (close(pfd2[1]) == -1)
        perror("close 6");

    if (wait(NULL) == -1)
        perror("wait 1");
    if (wait(NULL) == -1)
        perror("wait 2");
    if (wait(NULL) == -1)
        perror("wait 3");

    exit(EXIT_SUCCESS);
}

解决方法:

问题是您没有在进程3中关闭pfd [1],而是添加close(pfd [1]);.在该过程3中的情况0之后将对其进行修复.

在进程3中,该猫将从pfd [0]中读取,但是这些进程中有四个pfd [1]:

>流程0

这是主进程,该进程中的pfd [1]将在wait()之前由该close关闭.
>流程1

ls完成后,此过程中的pfd [1]将由操作系统自动关闭.
>流程2

pfd [1]在执行cat之前已经关闭.
>流程3

在wc运行时,pfd [1]在此进程中打开,这是此时发生的情况:

>在过程2中,cat尝试从pfd [1]中读取pfd [0]以获取数据
>在过程3中,wc尝试从pfd2 [1]读取pfd2 [0]以获取数据
>因为pdf [1]在进程3中仍处于打开状态,并且不会写入任何内容,所以从进程2(cat)中的pfd [0]中读取将永远等待
>因为进程3中的cat仍然存在,所以从进程3(wc)中的pfd2 [0]中读取将永远等待

如您所见,由于文件描述符泄漏,您在进程2(cat)和进程3(wc)之间陷入了僵局.要打破此僵局,您只需要在运行wc之前在进程3中关闭pfd [1],然后:

>进程1中的ls退出后,进程2中的cat将退出,因为没有剩余空间供其读取(cat)
>进程2中的cat退出后,进程3中的wc也将退出,因为没有剩余可读取的内容(wc)
>之后,主进程(父进程)将退出,程序将完成.

管道的读取端可能有多个写入端,除非所有这些写入端都关闭,否则文件末尾将不会传递到读取端,而读取器将仅等待更多数据来.如果什么都没有,那位读者将永远等待.

标签:c-3,linux,fork,pipe,exec
来源: https://codeday.me/bug/20191013/1907839.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有