当前位置: 首页 > 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错误?
  • Android交互
  • Fabric架构演变之路
  • input的行数自动增减
  • javascript 总结(常用工具类的封装)
  • orm2 中文文档 3.1 模型属性
  • Vue UI框架库开发介绍
  • Vue2.0 实现互斥
  • 持续集成与持续部署宝典Part 2:创建持续集成流水线
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 服务器从安装到部署全过程(二)
  • 警报:线上事故之CountDownLatch的威力
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 前端代码风格自动化系列(二)之Commitlint
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 异步
  • 用jquery写贪吃蛇
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 昨天1024程序员节,我故意写了个死循环~
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • ​一些不规范的GTID使用场景
  • #AngularJS#$sce.trustAsResourceUrl
  • #HarmonyOS:基础语法
  • #pragma 指令
  • %check_box% in rails :coditions={:has_many , :through}
  • (C语言)共用体union的用法举例
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (四)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (轉貼) UML中文FAQ (OO) (UML)
  • 、写入Shellcode到注册表上线
  • .NET 中让 Task 支持带超时的异步等待
  • .net连接MySQL的方法
  • .NET连接数据库方式
  • .NET实现之(自动更新)
  • ?php echo $logosrc[0];?,如何在一行中显示logo和标题?
  • @在php中起什么作用?
  • [ JavaScript ] JSON方法