进程间通信-匿名管道
来源:互联网 发布:linux qt调试器未设置 编辑:程序博客网 时间:2024/05/16 17:54
匿名管道
一、特点
1.只适合单向通信。(如果需要双向通信,则需要两个匿名管道来进行完成)
2.只适合具有血缘关系的进程进行通信
3.管道是文件,生命周期随进程,进程结束后,文件就不在了
4.管道是基于字节流方式来进行通信的
5.父进程和子进程访问的公共资源叫做临界资源,所有临界资源都是需要被保护起来的,多个进程进行访问时必须要保证原子性。(任一时刻保证只有一个人访问)
6.管道内部自己已经实现同步性,能保证数据的一致性。
另外,进程间的通信的本质是:两个进程看到了一份公共的资源。
二、管道的创建
1.由父进程创建,子进程继承父进程的文件描述符,指向同一个文件,一个用来读,一个用来写,适当的关闭相应的文件读写端。
函数功能:创建管道,使得__pipe[0]指向文件的读端,_pipe[1]指向文件的写端
参数:一个含有两个整型元素的数组
返回值:0正常 -1管道创建失败
2.管道的大小
测试匿名管道的大小:
#include<stdio.h>#include<unistd.h>#include<stdlib.h>int main(){ int fd[2]; int count=0; if(pipe(fd)<0) { perror("Fail to create pipe"); exit(1); } while(1) { write(fd[1],"a",sizeof(char)); printf("count=%d.\n",++count); } return 0;}
可知:管道的大小是:65536个字节=2的16次方个字节=64M
三、关于匿名管道读写的四种方式
使⽤用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):
1. 如果所有指向管道写端的⽂文件描述符都关闭了(管道写端的引⽤用计数等于0),⽽而仍然有进程 从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到⽂文件末尾⼀一样。
#include<stdio.h>#include<errno.h>#include<string.h>#include<sys/wait.h>#include<unistd.h>int main(){ int _pipe[2]; int ret=pipe(_pipe); if(ret==-1) { printf("create pipe error ! error code is :%d\n",errno); } pid_t id=fork(); if(id<0) { printf("fork error\n"); return 2; } else if(id==0)//child { close(_pipe[0]); int i=0; char * _mesg_c=NULL; while(i<10) { sleep(1); _mesg_c="i am child"; write(_pipe[1],_mesg_c,strlen(_mesg_c)+1); i++; } close(_pipe[1]); } else//father { close(_pipe[1]); char _mesg[100]; int j=0; printf("child id ;%d\n",id); while(j<100) { memset(_mesg,'\0',sizeof(_mesg)); read(_pipe[0],_mesg,sizeof(_mesg)-1); printf("%s:code count :%d\n",_mesg,j); j++; } } if(waitpid(id,NULL,0)<0) { printf("wait child sucessfully\n"); return 3; } return 0;}
可以看出父进程读取时,发生了阻塞,每隔一秒钟读取一次。
2.如果有指向管道写端的⽂文件描述符没关闭(管道写端的引⽤用计数⼤大于0),⽽而持有管道写端的 进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
#include<stdio.h>#include<errno.h>#include<string.h>#include<sys/wait.h>#include<unistd.h>int main(){ int _pipe[2]; int ret=pipe(_pipe); if(ret==-1) { printf("create pipe error ! error code is :%d\n",errno); } pid_t id=fork(); if(id<0) { printf("fork error\n"); return 2; } else if(id==0)//child { close(_pipe[0]); int i=0; char * _mesg_c=NULL; while(i<20) { if(i<10) { _mesg_c="i am child"; write(_pipe[1],_mesg_c,strlen(_mesg_c)+1); } sleep(1); i++; } // close(_pipe[1]); } else//father {/// sleep(3); close(_pipe[1]); char _mesg[100]; int j=0; printf("child id ;%d\n",id); while(j<20) { memset(_mesg,'\0',sizeof(_mesg)); read(_pipe[0],_mesg,sizeof(_mesg)-1); printf("%s:code count :%d\n",_mesg,j); j++; } } if(waitpid(id,NULL,0)<0) { printf("wait child sucessfully\n"); return 3; } return 0;}
3.如果所有指向管道读端的⽂文件描述符都关闭了(管道读端的引⽤用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终⽌止。
#include<stdio.h>#include<errno.h>#include<string.h>#include<sys/wait.h>#include<unistd.h>int main(){ int _pipe[2]; int ret=pipe(_pipe); if(ret==-1) { printf("create pipe error ! error code is :%d\n",errno); } pid_t id=fork(); if(id<0) { printf("fork error\n"); return 2; } else if(id==0)//child { close(_pipe[0]); int i=0; char * _mesg_c=NULL; while(i<20) { if(i<10) { _mesg_c="i am child"; write(_pipe[1],_mesg_c,strlen(_mesg_c)+1); }// sleep(1); i++; } } else//father { close(_pipe[1]); char _mesg[100]; int j=0; printf("child id ;%d\n",id); while(j<3) { memset(_mesg,'\0',sizeof(_mesg)); read(_pipe[0],_mesg,sizeof(_mesg)-1); printf("%s:code count :%d\n",_mesg,j); j++; } close(_pipe[0]); } if(waitpid(id,NULL,0)<0) { printf("wait child sucessfully\n"); return 3; } return 0;}
进程异常终止
4.如果有指向管道读端的⽂文件描述符没关闭(管道读端的引⽤用计数⼤大于0),⽽而持有管道读端的 进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再 次write会阻塞,直到管道中有空位置了才写⼊入数据并返回。
#include<stdio.h>#include<errno.h>#include<string.h>#include<sys/wait.h>#include<unistd.h>int main(){ int _pipe[2]; int ret=pipe(_pipe); if(ret==-1) { printf("create pipe error ! error code is :%d\n",errno); } pid_t id=fork(); if(id<0) { printf("fork error\n"); return 2; } else if(id==0)//child { close(_pipe[0]); int i=0; char * _mesg_c=NULL; while(i<20) { _mesg_c="i am child"; write(_pipe[1],_mesg_c,strlen(_mesg_c)+1); sleep(1); i++; } } else//father { close(_pipe[1]); char _mesg[100]; int j=0; printf("child id ;%d\n",id); while(j<5) { memset(_mesg,'\0',sizeof(_mesg)); read(_pipe[0],_mesg,sizeof(_mesg)-1); printf("%s:code count :%d\n",_mesg,j); j++; } } if(waitpid(id,NULL,0)<0) { printf("wait child sucessfully\n"); return 3; } return 0;}
写入端发生阻塞,一直等待读取。
0 0
- 进程间通信-匿名管道
- 进程间通信 - 匿名管道
- 进程间通信匿名管道
- 进程间通信-匿名管道
- 进程间通信:匿名管道通信
- 进程间通信之匿名管道通信
- 进程通信-匿名管道
- 进程通信 - 匿名管道
- 进程间通信之管道通信(匿名管道)
- 匿名管道--进程间的通信
- 进程间通信-匿名管道
- 通过匿名管道实现进程间通信
- 进程间通信 - 匿名管道实现
- 进程间通信详解 - 匿名管道实现
- 进程间通信——匿名管道
- 通过匿名管道实现进程间通信
- 进程间通信详解 - 匿名管道实现
- 进程间通信 - 匿名管道实现
- Android 笔记
- 浅谈jsp、freemarker、velocity区别
- zookeeper<集群环境搭建>
- Java守护线程简介
- 剑指offer 22---判断元素出栈、 入栈顺序的合法性
- 进程间通信-匿名管道
- Java transient关键字解析
- IntelliJ远程调试教程
- Linux远程执行hostname命令,监控服务器是否被篡改
- WebService教程详解
- Hadoop和Spark的处理模型比较
- docker build命令详解
- mac 下安装php7全过程
- Disruptor简介