博客
关于我
进程间通信( 管道 )
阅读量:526 次
发布时间:2019-03-07

本文共 4187 字,大约阅读时间需要 13 分钟。

进程间通信( 管道 )


前言

  进程间通信: 进程间的几种通信方式的学习(管道, 共享内存, 消息队列, 信号量)
   为什么进程间无法直接进行通信?
    因为进程之间具有独立性, 每个进程访问的都是自己的独立的虚拟地址空间, 使用的都是虚拟地址, 通过页表映射到物理内存. 因此就算将数据的内存地址交给其他进程, 其他进程也无法访问(当然其实也无法直接给), 只能通过操作系统提供的几种方式来进行.
本质上来说是操作系统为多个进程提供了一处公共的数据传输媒介(内存)。

一、管道

管道 用于传输数据
特性 半双工通信–可以选择方向的单向通信
本质 管道就是内核中的一块缓冲区(内存)
分类 匿名管道,命名管道
  匿名管道:管道没有名字--缓冲区没有标识符;
   只能用于具有亲缘关系的进程间通信
 命名管道:管道具有标识符;
   可用于同一主机上的任意进程间通信
 匿名管道:
int pipe(int pipefd[2])

在这里插入图片描述

在这里插入图片描述

 pipefd[0]--读
 pipefd[1]--写
 返回值:成功返回0;失败返回-1;
  匿名管道一定要在创建子进程之前创建

代码如下(示例):

1 #include 
2 #include
3 #include
4 #include
5 int main() 6 { 7 int pipefd[2]; 8 int ret = pipe(pipefd); 9 if(ret < 0){ 10 perror("pipe error"); 11 return -1; 12 } 13 pid_t pid = fork(); 14 if(pid < 0){ 15 perror("fork error"); 16 exit(-1); 17 }else if(pid == 0){ 18 //child 19 char buf[1024] = { 0}; 20 int ret = read(pipefd[0], buf, 1023); 21 if(ret < 0){ 22 perror("read error"); 23 return -1; 24 } 25 printf("buf:%s\n", buf); 26 }else{ 27 //parent 28 char *ptr = "今天好困呐!!\n"; 29 int ret = write(pipefd[1], ptr, strlen(ptr)); 30 if(ret < 0){ 31 perror("write error"); 32 return -1; 33 } 34 printf("写入成功\n"); 35 } 36 return 0; 37 }

结果:

在这里插入图片描述

 通常情况下, 父子进程运行的顺序是不一定的, 一般情况下, 父进程先于子进程运行. 但在这里, 子进程明显先于父进程运行, 这是由于管道的特性所决定的.
管道中的读取特性 :
  1.若管道中没有数据则read会阻塞,管道中数据满了,则write会阻塞。
  2.若管道的所有读端被关闭,则write会触发异常--导致进程退出;
  3.若管道的所有写端被关闭,则read读完所有数据后返回0;

 1.若管道中没有数据则read会阻塞,管道中数据满了,则write会阻塞。

在这里插入图片描述

 2.若管道的所有读端被关闭,则write会触发异常–导致进程退出;
在这里插入图片描述

 3.若管道的所有写端被关闭,则read读完所有数据后返回0;
在这里插入图片描述

 shell中的管道符: | --连接两个命令,将前边命令的结果交给后边命令进行处理
ps -ef | grep pipe模拟实现
ps -ef:将系统中的进程信息写入标准输出
grep pipe:不断从标准输入读取数据,进行匹配过滤.
使用管道连接两个命令之后,将ps进程原本要写入标准输出的数据,不再 写入标准输出,而是通过管道写入端写入管道。grep进程原本从标准输入读取数据,修改为从管道读取端读取数据,进行匹配过滤
1.当前进程作为shell进程,所有命令都是子进程完成的;
2.创建匿名管道;
3.创建一个子进程,先进行标准输出重定向到管道写入端,然后经过程序替换运行ps -ef指令;
4.创建一个子进程,先进行标准输入重定向到管道读取端,然后经过程序替换运行grep pipe指令;
5.子进程等待两个父进程退出;

注意:在进程中把不使用的管道一端一定要关掉,防止一些不必要的问题

1 #include 
2 #include
3 #include
4 #include
5 int main() 6 { 7 int pipefd[2]; 8 int ret = pipe(pipefd); 9 if(ret < 0){ 10 perror("pipe error"); 11 return -1; 12 } 13 if(fork() == 0){ 14 dup2(pipefd[1], 1); 15 execlp("ps", "ps", "-ef", NULL); 16 exit(-1); 17 } 18 if(fork() == 0){ 19 dup2(pipefd[0], 0); 20 execlp("grep","grep", "pipe", NULL); 21 exit(-1); 22 } 23 wait(NULL); 24 wait(NULL); 25 return 0; 26 }

在这里插入图片描述

 命名管道:内核中的缓冲区具有标识符,能够被其他进程找到,因此可用于同一主机上的任意进程间通信
命名管道具有标识符,这个标识符是可见于文件系统的管道文件,但是要注意,这个文件只是一个标识符,只是为了让多个进程 可以通过打开同一个管道文件进而访问内核中的同一块缓冲区进行通信而已。

代码操作:

int mkfifo(const char*pathname,mode_t mode);

在这里插入图片描述

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 int main() 8 { 9 umask(0); 10 char *fifo_name = "./test.fifo"; 11 int ret = mkfifo(fifo_name, 0664); 12 if(ret < 0 && errno != EEXIST){ 13 perror("mkfifo error"); 14 return -1; 15 } 16 //open(文件名, 打开方式, 权限) 17 int fd = open(fifo_name, O_RDONLY); 18 if(fd < 0){ 19 perror("open error"); 20 return -1; 21 } 22 printf("open fifo success\n"); 23 return 0; 24 }

程序阻塞

在这里插入图片描述
 命名管道的打开特性:
  如果命名管道以只读的方式打开,会阻塞直到这个管道被以写的方式打开;
  如果命名管道以只写的方式打开,会阻塞直到这个管道被以读的方式打开;

在这里插入图片描述

写端 :

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 int main() 9 { 10 umask(0); 11 char *fifo_name = "./test.fifo"; 12 int ret = mkfifo(fifo_name, 0664); 13 if(ret < 0 && errno != EEXIST){ 14 perror("mkfifo error"); 15 return -1; 16 } 17 int fd = open(fifo_name, O_WRONLY); 18 if(fd < 0){ 19 perror("open error"); 20 return -1; 21 } 22 while(1){ 23 char buf[1024] = { 0}; 24 scanf("%s", buf); 25 int ret = write(fd, buf, strlen(buf)); 26 if(ret < 0){ 27 perror("write error"); 28 return -1; 29 } 30 } 31 close(fd); 32 return 0; 33 }

在这里插入图片描述

转载地址:http://pybnz.baihongyu.com/

你可能感兴趣的文章
MySQL 添加列,修改列,删除列
查看>>
mysql 添加索引
查看>>
MySQL 添加索引,删除索引及其用法
查看>>
mysql 状态检查,备份,修复
查看>>
MySQL 用 limit 为什么会影响性能?
查看>>
MySQL 用 limit 为什么会影响性能?有什么优化方案?
查看>>
MySQL 用户权限管理:授权、撤销、密码更新和用户删除(图文解析)
查看>>
mysql 用户管理和权限设置
查看>>
MySQL 的 varchar 水真的太深了!
查看>>
mysql 的GROUP_CONCAT函数的使用(group_by 如何显示分组之前的数据)
查看>>
MySQL 的instr函数
查看>>
MySQL 的mysql_secure_installation安全脚本执行过程介绍
查看>>
MySQL 的Rename Table语句
查看>>
MySQL 的全局锁、表锁和行锁
查看>>
mysql 的存储引擎介绍
查看>>
MySQL 的存储引擎有哪些?为什么常用InnoDB?
查看>>
Mysql 知识回顾总结-索引
查看>>
Mysql 笔记
查看>>
MySQL 精选 60 道面试题(含答案)
查看>>
mysql 索引
查看>>