为什么需要关闭不使用的读端和写端?不关闭行不行?

我们看下面一段代码

 #include<stdio.h>#include<sys/types.h>#include<sys/wait.h>#include<unistd.h>#include<stdlib.h>#include<string.h>int main(void){pid_t pid;int fp[2];int ret=pipe(fp);int i;char *s[5];char *t[5];s[0]="ls";s[1]="-l";s[2]=NULL;t[0]="wc";t[1]=NULL;for(i=0;i<2;i++){   pid=fork();if(pid==-1){   perror("pid error:");exit(1);}if(pid == 0){break;}}if(i == 0){close(fp[0]);dup2(fp[1],STDOUT_FILENO);execvp(s[0],s);}else if(i == 1){close(fp[1]);dup2(fp[0],STDIN_FILENO);execvp(t[0],t);}int set;if(pid > 0){do{set = waitpid(-1,NULL,WNOHANG);}while(set == 0);}return 0;}

运行结果为

输出正常,但如果对整个main里的代码加上while循环的话结果就不一样了

 #include<stdio.h>#include<sys/types.h>#include<sys/wait.h>#include<unistd.h>#include<stdlib.h>#include<string.h>int main(void){while(1){pid_t pid;int fp[2];int ret=pipe(fp);int i;char *s[5];char *t[5];s[0]="ls";s[1]="-l";s[2]=NULL;t[0]="wc";t[1]=NULL;for(i=0;i<2;i++){   pid=fork();if(pid==-1){   perror("pid error:");exit(1);}if(pid == 0){break;}}if(i == 0){close(fp[0]);dup2(fp[1],STDOUT_FILENO);execvp(s[0],s);}else if(i == 1){close(fp[1]);dup2(fp[0],STDIN_FILENO);execvp(t[0],t);}int set;if(pid > 0){do{set = waitpid(-1,NULL,WNOHANG);}while(set == 0);}}return 0;}

没有任何结果输出

通过 ps aux 查看进程会发现有很多的阻塞的wc进程

为何会出现这种情况?

这里就是涉及到标题了,为何要把不使用的读写端关闭,上面的程序没有把父进程对pipe读写端关闭,使得读写端的计数在最小的时候都>0。

当pipe写端引用计数>0时,读端读完管道里的数据后会阻塞等待写端写入。
当pipe写端引用计数为0时,读端读完数据直接返回0,进程结束。

所以当父进程没有关闭读写端的时候,wc进程读完管道里的内容后会阻塞等待父进程写端写入,而我们程序的父进程明显没有写的操作,所有wc就会一直阻塞等待了。
但是为何没有while循环就会有正常的结果输出?

当一个进程结束后,会释放掉它所占有的文件描述符和用户空间,只保留pcb,里面保存着导致它结束的信号,变成僵尸进程等待父进程收尸。所以没有while循环的话当父进程结束后,pipe写端的引用计数就变为0,wc进程就不会阻塞等待了,所以就会有正常结果输出。

所以,我们加入父进程对于pipe读端写端的close操作就好了

 #include<stdio.h>#include<sys/types.h>#include<sys/wait.h>#include<unistd.h>#include<stdlib.h>#include<string.h>int main(void){while(1){pid_t pid;int fp[2];int ret=pipe(fp);int i;char *s[5];char *t[5];s[0]="ls";s[1]="-l";s[2]=NULL;t[0]="wc";t[1]=NULL;for(i=0;i<2;i++){   pid=fork();if(pid==-1){   perror("pid error:");exit(1);}if(pid == 0){break;}}if(i == 0){close(fp[0]);dup2(fp[1],STDOUT_FILENO);execvp(s[0],s);}else if(i == 1){close(fp[1]);dup2(fp[0],STDIN_FILENO);execvp(t[0],t);}int set;if(pid > 0){do{close(fp[0]);close(fp[1]);set = waitpid(-1,NULL,WNOHANG);}while(set == 0);}}return 0;}

可以看到输出正确

综上,在我们使用管道进行进程间通信时,一定要对不使用的读写端进行close操作,否则会因为读写端引用计数>0,出现一些BUG。

对于不使用的管道读写段需要关闭的思考相关推荐

  1. Linux学习笔记-匿名和命名管道读写的相同点及不同点

    目录 理论 例子 理论 匿名和命名管道读写的相同性 1.默认都是阻塞性读写: 2.都适用于socket的网络通信: 3.阻塞不完整管道(有一段关闭) a.单纯读时,在所有数据被读取后,read返回0, ...

  2. 进程返回linux系统编程之管道(二):管道读写规则和Pipe Capacity、PIPE_BUF

    题记:写这篇博客要主是加深自己对进程返回的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢. 一. 当没有数据可读时 O_NONBLOCK disable:read调用阻塞,即进程暂停 ...

  3. linux系统编程之管道(二):管道读写规则和Pipe Capacity、PIPE_BUF

    一. 当没有数据可读时 O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止. O_NONBLOCK enable:read调用返回-1,errno值为EAG ...

  4. Linux编程:多个子进程与父进程使用匿名管道读写

    编写程序,在程序中父进程先后创建子进程1和子进程2.父子三个进程并发执行,并利用同一个匿名管道通信:两个子进程分别向管道写一则信息(内容自定,但要求包含子进程信息):父进程从管道读出信息并显示出来(要 ...

  5. 操作系统8-死锁和进程通信----(库函数scanf和printf是基于管道读写实现的!

    大纲: 死锁概念及死锁处理方法 银行家算法 死锁检测 进程通信方法:信号.管道.消息队列.共享内存 一.死锁 背景 可重用资源:资源不能被删除且任何时刻只能有一个进程使用,进程释放资源后其他进程可重用 ...

  6. C/C++编程 获取调用其他程序的输出、匿名管道读写

    用途 调用外部命令来协助完成某些功能 如很多扫描工具实际上是调用nmap来帮助扫描任务的 #include <stdio.h> //#include <string.h> #i ...

  7. 面试必问:读写一致性,你需要思考的问题

    先说明下,本文要讨论的多线程读写是指一个线程写,一个或多个线程读,不包括多线程同时写的情况. 试想下这样一个场景:一个线程往hashmap中写数据,一个线程往hashmap中读数据. 这样会有问题吗? ...

  8. 初步认识Volatile-一段代码引发的思考

    下面这段代码,演示了一个使用volatile以及没使用volatile这个关键字,对于变量更新的影响 public class VolatileDemo { public /*volatile*/ s ...

  9. 【中科院信工所】-2021考研经验-记录一段每天都在思考如何学习的日子

    今天出了录取名单,二战上岸,突然觉得综艺,B站都好没意思,也不知道该干什么,索性记录一下备考的这段日子,碎碎念可能会很多,想看干货可以直接点标题阅读. 目录 基本情况 初试备考 数学一(109分) 英 ...

  10. 05 高性能网络设计专栏-网络原理

    以下是在零声教育的听课记录. 如有侵权,请联系我删除. 链接:零声教育官网 还有很大一部是是借鉴了这个博客的总结:CSDN博主「cheems~」的原创文章 目录 1. websocket协议与服务器实 ...

最新文章

  1. Reddit年度盘点:2019年最佳机器学习项目
  2. ThumbProcess.exe错误的解决方法
  3. Mac环境下sublime实现列选择或编辑的方法
  4. MyBatis-20MyBatis高级结果映射【一对一映射(4种方式)】
  5. python 回文数
  6. python中str和repr_python中str()和repr()函数的区别
  7. WinAPI: midiOutReset - 重置输出设备
  8. C语言试题七十二之请编写函数判断三角形的类型,并输出其面积和类型。
  9. 解决:Caused by: java.lang.UnsupportedOperationException: null
  10. 表单内如何直接贴图而不用上传图片_重磅更新|偷偷告诉你,表单大师官网改版啦啦啦啦...
  11. nagios 监控出现It appears as though you do not have permission
  12. Git分支基本命令+coding webhook+lnmp
  13. 旅游展示网站-前端网页设计技术完整精美源码HTML+CSS+JS
  14. 数字基带调制解调matlab仿真,我的基于MATLAB仿真的数字调制与解调设计
  15. Google的愚人节
  16. 技术人的充电时刻,24个精彩研发案例在等你
  17. 使用完整拼音查找汉字(完整拼音,不是网上散布的首字符拼音那种方法)
  18. Jetpack Compose——Text(文本)的使用
  19. 适合python的vim设置
  20. UML软件工程--类图

热门文章

  1. python 中的百分号用法,Python中%是什么意思?python中百分号如何使用?
  2. (17)2020-12-23(三栏布局、视口、百分比布局、媒体查询)
  3. hotnets 2018 Gearing up for the 21st century space race 阅读报告
  4. SVN实例--结合Myeclipse
  5. PPmoney陈宝国:严守行业底线 不往兜里多揣一分钱
  6. Apache Way -- Meritocracy
  7. mysql limit 5 5 正确_关于语句limit 5,5,说法正确的是_学小易找答案
  8. 【SIMULINK】创建及封装子系统
  9. 浏览器在浏览新的网页时不会自己跳转到新的网页怎么办?
  10. 使用485通信远程抄表,获取电能表显示的千瓦时数据