免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2078 | 回复: 0
打印 上一主题 下一主题

shell中管道的原理 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-02-21 16:13 |只看该作者 |倒序浏览
    管道是linux中一个很重要的命令行操作,因为linux的每个命令都以完成一个任务为目的,只有把些命令组合起来才能做复杂的工作,当然这种方式也提供了很大的灵活性。那么bash中的管道是通过什么实现的呢? 先看一个简单的管道的例子:
               
               
                #include unistd.h>
int fd[2];
void run_ls()
{
      dup2(fd[1],1);
     close(fd[0]);
     close(fd[1]);
     execve("/bin/ls",NULL,NULL);
}
void run_wc()
{
      dup2(fd[0],0);
     close(fd[0]);
     close(fd[1]);
     execve("/usr/bin/wc",NULL,NULL);
}
int main()
{
    pipe(fd);
    if(fork()==0)
        run_ls();
    else
        run_wc();
     return 0;
}

    这个程序的执行结果等效于ls|wc,从代码上看,主程序调用pipe来创建一个管道,如下图:

   对fd[1]进行写操作时会把数据写到内核中的pipe对应的buffer中,而对fd[0]进行读操作时,就是从pipe的buf中读取数据,这样就把fd[0]和fd[1]连接成一个"管道".
   继续看main函数中的代码,fork调用创建出子进程,子进程会继承父进程的文件描述符表,创建子进程后管道的状态是:

    两个进程中的fd[0],fd[1]的值是相同的,它们所指向的内核中的表示文件的结构体也是相的。先不看dup2调用,在子进程关闭fd[1],父进程关闭fd[0]后:

这样在子进程和父进程之间就建立起一个管道,子进程向fd[1]写的数据,父进程可以通过读fd[0]读出。再看dup2调用,父进程中又把标准输入对应的文件结构体复制成了fd[0]对应的,子进程中把标准输出对应的文件结构体复制成了fd[1]对应的,这个结构体中包含了对文件的操作函数。这样子进程中写0号文件描述符的数据实际就会写到内核中的pipe的buf中,而父进程从1这个文件描述符对应的文件读取数据,现在1已经不再指向标准输出,而是指向了pipe的buf。
   虽然这个例子很简单,但已经可以说明bash中管道的原理。从上面的分析我们可以看出,linux中创建进程是从父进程"fork"出来,然后再execve,而不是在创建时就指定它要运行的函数,完成独立地创建,这样天然的进程的继承关系,为管道的实现提供了很大的方便,因为管道的实现利用了子进程继承父进程的文件描述符表这一特性。
   关于内核中对pipe的支持,参见下一篇文章:linux内核中pipe的实现
   图片出自APUE 2
   


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/22326/showart_481830.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP