当前位置: 首页 > news >正文

(转)关于pipe()的详细解析

kevintz 2000.8.23
int pipe(int fd[2])函数在内核生成一个管道,如图。返回的
fd[0]描述符用于从管道读内容,fd[1]用于向管道写。
---------------------
fd[0]---------------------
读的时候,如果管道没数据,读进程阻塞。如果写的时候管道满,
写进程阻塞。可以把fd[0], fd[1]设成是非阻塞,在上面的阻塞情形,
不再阻塞进程,立刻返回。
管道的某一端只能是只读或只写,如果向fd[0]写和向fd[1]读都会
出错,返回-1。
另外,fork()调用生成的子进程和原来的父进程是共用这条管道的,
并不是又生成另一条管道。如图所示:
+------------------------+
| |
------------- +- ----------- 父 | fd[0] || fd[0] | 子
| | ----------- | | | |
| fd[1] |------------------------+ +--- | fd[1] |
| ........ | | ..... |
而且对于子进程来说,fd[0]也是用于只读,fd[1]也是用于写,因为
它们的指向和父进程里是一样的。
下面来分析一下网友startrek写的程序,并分析为何出错。
int main(){
int fd[2];
char buf[200],len;
int status;
if(pipe(fd)==0){
if(fork()==0){
len=read(fd[0],buf,sizeof(buf));
buf[len]=0;
printf("[Child]:%s\n",buf);
sprintf(buf,"answer from child");
write(fd[1],buf,strlen(buf));
}
else{
sprintf(buf,"string from parent");
write(fd[1],buf,strlen(buf));
sleep(2);
len=read(fd[0],buf,sizeof(buf)); // ***
buf[len]=0;
printf("[Parent]:%s\n",buf);
}
}
wait(&status);
}
[情况1]
如果注释掉sleep(2);这一句,父进程就会接收自己传给子进程的
字符串,显示
[Parent]:string from parent
而子进程就因为无数据读而阻塞。这说明父进程和子进程之间只有
一条管道队列进行双向传输,父进程读取数据后管道为空,所以子
进程阻塞。
kevintz分析:其实这个结果是正确的。原因如下:去掉sleep(2)后,当父进
程写fd[1]后,继续运行read(..),所以父进程把自己写进去的东西读
了出来。而到子进程运行时,就因为没数据读而阻塞了。注意:管道
只能是单向传输的!
[情况2]
但如果将标有***的一句改为
len=read(fd[1],buf,sizeof(buf)),而sleep(2);不注释,就会有
下面奇怪的显示结果:
[Child]:string from parent
[Parent]:string from parent
按道理说在子进程退出后,管道中应该只有"answer from child"。
kevintz分析:这个结果也是正确的。其实子进程是已经读到了父进程的内容,
而且已经写回了管道里。不过因为不论是父进程还是子进程对fd[1]读,
都是出错的,返回-1,而buf里的东西还是sprintf进去的东西,没变。
反而buf[len]就是buf[-1]=0这句有潜在的危险。然后你把buf打印,所
以还是原来的内容。管道的某一端都只能是只读或只写的!
[情况3]
和情况2相同,在最后加3行,即父进程使用fd[0]进行read,其
显示结果为
[Child]:string from parent
[Parent]:string from parent
[Parent]:answer from child
kevintz分析:这个例子就正好做了情况2的解析。说明子进程的确收到了父进程
的信息,而且写回了管道,而父进程应该用read(fd[0]...)来读的,所
以读到了子进程写回的信息。
[情况4]
如果一开始父进程多传一个串"string 2 from parent",其结果
就更复杂。
kevintz分析:呵呵:),多传一个串,结果慢慢去分析吧................
总结:
其实这种通信,应该用两条管道来形成一个双向的交流管道,而不应该用一
条管道。
当然你可以用信号量来同步管道的使用,但太复杂,而且不实际。双向管道
可以这样实现。
int main()
{
int fd1[2],fd2[2],len;
char buf[128];
int status;
pipe(fd1);
pipe(fd2);
if( fork() == 0)
{
close(fd1[0]);
close(fd2[1]);
len=read(fd2[0], buf, 128);
buf[len]=0;
printf("[Child]:%s\n",buf);
sprintf(buf,"answer from child");
write(fd1[1], buf, strlen(buf));
close(fd2[0]);
close(fd1[1]);
}
else
{
close(fd1[1]);
close(fd2[0]);
sprintf(buf, "Hello from parent");
write(fd2[1], buf, strlen(buf));
len=read(fd1[0],buf,sizeof(buf));
buf[len]=0;
printf("[Parent]:%s\n",buf);
close(fd1[0]);
close(fd2[1]);
}
wait(&status);
exit(0);
}
--
※ 修改:.kevintz 于 Aug 23 11:08:13 修改本文.[FROM: 61.140.71.100]

相关文章:

  • Gephi 网络可视化——调整节点大小
  • 哎呀哎呀哎呀~,我爱上了事件
  • Gephi 网络可视化——设置节点颜色
  • 3个字节的空txt文本文件
  • 上班久坐族的福利
  • 微信朋友圈数据挖掘
  • Microsoft SQL Server事务日志的应用
  • 微信自动回复天气预报
  • linux下巧用tail命令 创建自解压tar文件
  • itchat 同时实现自动回复和定时任务
  • 恢复SQL2005误删除的数据
  • 国家地区标准代码(国际域名缩写)
  • 提高你的调试代码的效率
  • python 代码计时
  • 如何处理创建DB2工具目录数据库的时候遇到的SQL1005N错误?
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • android百种动画侧滑库、步骤视图、TextView效果、社交、搜房、K线图等源码
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • export和import的用法总结
  • HTML5新特性总结
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • java取消线程实例
  • MySQL的数据类型
  • Next.js之基础概念(二)
  • python学习笔记 - ThreadLocal
  • vue-router 实现分析
  • 笨办法学C 练习34:动态数组
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 译米田引理
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • #每日一题合集#牛客JZ23-JZ33
  • (145)光线追踪距离场柔和阴影
  • (3)STL算法之搜索
  • (LNMP) How To Install Linux, nginx, MySQL, PHP
  • (MATLAB)第五章-矩阵运算
  • (八)Spring源码解析:Spring MVC
  • (多级缓存)多级缓存
  • (二)换源+apt-get基础配置+搜狗拼音
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (十) 初识 Docker file
  • (小白学Java)Java简介和基本配置
  • .Net Core与存储过程(一)
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .NET Micro Framework 4.2 beta 源码探析
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • .NET6使用MiniExcel根据数据源横向导出头部标题及数据
  • .NET应用架构设计:原则、模式与实践 目录预览
  • .net知识和学习方法系列(二十一)CLR-枚举
  • .Net转前端开发-启航篇,如何定制博客园主题