1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 进程间通信(IPC机制)——管道

进程间通信(IPC机制)——管道

时间:2019-10-04 11:41:44

相关推荐

进程间通信(IPC机制)——管道

1.管道的特点

(1)无论有名还是无名,写入管道的数据都在内存中。

(2)管道是一种半双工通信方式(通信方式有单工(固定接收方发送方,接收方只能接收,发送方只能发送)、半双工(如同对讲机,两端可以切换写入和接收)、全双工(每端都可以接收和写入,且可以同时进行))。

(3)有名和无名管道的区别:有名可以在任意进程间使用,而无名只能在父子进程间。

(4)对于管道,我们只能以只读打开或者只写打开。

(5)有名管道得需要读和写都打开,否则只以读打开或者只以写打开都会阻塞。

(6)管道中没有数据时,读管道read会发生阻塞,直至管道被写入数据,读出数据,再次阻塞。如果写端被关闭,读端read返回值会成为0。如果读端被关闭,写端向管道写入数据后会自动退出。

(7)管道写满后,写端会阻塞。

(8)由于管道的数据都在内存中,所以查看管道大小总是0。

管道的实现:

写入从头指针开始,读取从尾指针开始。写入之后,头指针挪动,读取之后尾指针挪动。如果是头指针赶上尾指针,那么管道被写满,写就会被阻塞。如果是尾指针赶上头指针,那么管道为空,read阻塞。

管道可以用来在两个进程之间传递数据,如: ps -ef | grep “bash”, 其中‘|’就是管道,其作用就是将 ps 命令的结果写入管道文件,然后 grep 再从管道文件中读出该数据进行过滤。

管道大小是可以查看的,如下图可以看到管道512字节为一个单位,乘以8就是整个管道大小。

2.有名管道

2.1有名管道的创建和头文件

有名管道可以在任意两个进程之间通信

有名管道的创建:

(1)命令创建: mkfifo + 管道名

(2)系统调用创建

#include <sys/types.h>#include <sys/stat.h>//filename 是管道名 mode 是创建的文件访问权限int mkfifo( const char *filename, mode_t mode);

2.2有名管道的使用

进程 a 从键盘获取的数据循环传递给另一个进程 b。

我们可以用创建一个文件,a从键盘获取字符串存放到文件中,b从文件中读取。但是文件是存在磁盘上的,速度没有管道快,而且从文件读不到数据不会等待,但是管道不一样,b从管道读不到数据会阻塞,直到a又向管道中写入数据。

首先用命令mkfifo+管道名称创建管道

写端代码:

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<assert.h>#include<fcntl.h>#include<sys/stat.h>int main(){int fd = open("fifo",O_WRONLY);assert(fd != -1);printf("open FIFO success\n");while(1){printf("please input:\n");char buff[128] = {0};fgets(buff,128,stdin);write(fd,buff,strlen(buff)-1);if(strncmp(buff,"end",3)==0){break;}}close(fd);exit(0);}

读端代码:

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<assert.h>#include<fcntl.h>#include<sys/stat.h>int main(){int fd = open("fifo",O_RDONLY);assert(fd != -1);printf("FIFO open success\n");while(1){char buff[128] = {0};int n = read(fd,buff,127);if(n <= 0 || (strncmp(buff, "end", 3)==0)){break;}printf("%s\n",buff);}close(fd);exit(0);}

(1)如果读端或者写端先打开,那么将会在open阻塞住 ,直至另一端也打开管道。

(2)写端和读端都打开后,读端会在read处阻塞,写端向管道中写入数据后,读端才正常执行read,执行完继续在read阻塞。

(3)如果读端关闭,写端在向管道输入数据后会触发信号(SIGPIPE)自动退出。

(4)如果写端关闭,读端read函数值会返回0。

当写端和读端都在打开着,管道中的数据如果没有及时读出,不会消失。比如将读端加上休眠10s,代码如下:

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<assert.h>#include<fcntl.h>#include<sys/stat.h>int main(){int fd = open("fifo",O_RDONLY);assert(fd != -1);printf("FIFO open success\n");while(1){char buff[128] = {0};int n = read(fd,buff,127);if(n <= 0 || (strncmp(buff, "end", 3)==0)){break;}printf("%s\n",buff);sleep(10);}close(fd);exit(0);}

写端和读端执行情况:

发现,在读端还没来得及读走管道数据的时候写端再次向管道写入数据,管道中没读走的数据会被读端下一次读走。

3.无名管道

无名管道主要应用于父子进程间的通信。

无名管道的创建:

#include <unistd.h>2. /*3. pipe()成功返回 0,失败返回-14. fds[0]是管道读端的描述符5. fds[1]是管道写端的描述符6. */7. int pipe( int fds[2]);

代码演示:

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<assert.h>int main(){int fd[2];int res = pipe(fd);assert(res != -1);pid_t pid = fork();assert(pid != -1);if(pid == 0){close(fd[1]);char buff[128] = {0};read(fd[0],buff,127);printf("child read:%s\n",buff);close(fd[0]);}else{close(fd[0]);char buff[128] = {0};printf("please input(less 128):\n");fgets(buff,128,stdin);write(fd[1],buff,strlen(buff)-1);close(fd[1]);}exit(0);}

执行结果:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。