【Linux】进程间通信--管道

一.进程产生
1.通信的目的

让两个或多个进程实现实现数据传输,资通源共享,通知事件,进程控制

2.进程间为什么不能进行直接通信

在我们学完进程后,都知道每个进程是独立的都有自己的PCB,有自己独立的地址空间,就连父子进程也是数据写实拷贝,更别说其他进程了,因为在每个进程看来,自己享有所有的内存资源,所以两个资源是不可能直接通信的,所以我们就必须让两个或多个进程看到一份共同的资源,这样才能实现进程通信

二.进程通信的分类
1.管道
管道就是把一个进程连接到另一个进程的一个数据流称为管道。管道的本质是内核的一段缓存

(1)匿名管道

#include <unistd.h>

int pipe[ int f[2] ];  pipe就是分别用读和写的方式打开文件参数为打开文件的描述符,fd[0]表示读端,fd[1]表示写端。返回值:成功返回0.,返回错误代码

先用pipe分别用读和写的方式打开一个文件,因为是以不同方式打开两次所以有两个fd,再利用fork创建子进程,可以在子进程中向文件写东西(关闭读端),在父进程中读取文件的东西,这样就实现了不同进程访问同一个文件,从而达到进程通信的目的

管道的内核缓存大小是65536字节
往管道中写入数据是,一次写入大小不要超过PIPE_BUF(4096)

匿名管道实现的原理

管道的四种情况

  • 写端一直写,读端不读也不关,写端会一直写满,写端阻塞
  • 读端一直读,写端一直写,写端突然不写,但也不关,读端一直读,当管道为空时,读端就会阻塞
  • 写端不写,还关了,读端一直读,读到0,表示读到管道结尾
  • 写端一直写,读端不读,且关闭读端,写端会被操作系统发送信号异常终止(因为没人读,操作系统认为是浪费资源)
特点
  • 管道自带互斥和同步机制
  • 只有有血缘关系的两个进程,常见于父子进程通信
  • 一般而言,进程退出,管道释放,因此管道生命周期随进程
  • 管道能提高面向字节流的服务
  • 只能进行单向通信
  • 管道是半双工的,数据只能向一个方向流动,需要双方通信时,需要建立起两个管道
解释
  1. 同步:多个进程需要相互配合完成一次任务
  2. 互斥:由于各个进程需要访问资源,而资源只能被一个进程访问,各个进程需要相互竞争这些资源,将这种关系称为互斥
  3. 数据不一致,读写双方因访问共同资源而导致的数据不一致问题
  4. 把两个毫不相干的进程看到的公共资源叫临界资源
  5. 把访问临界资源的代码叫临界区
  6. 访问资源的原子性:在进程某些资源的操作时,要么就不做,要做就做完,不会有中间状态,这种状态叫做原子性
  7. 文件描述符复制 dup2(old,new)让new的指针指向old的文件表
(2)命名管道(FIFO)

解决匿名管道不能让没有亲缘关系的进程的进程拿到换到内核缓存

创建一个管道文件

用命令行创建:mkfilfo filename

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo(char *name,mode_t mode)//先用mkfifo创建共同访问的文件,管道再在两个进程中打开这个文件(一个以只读方式,一个为只写),这样就创建出了一个命名管道

用命名管道实现文件拷贝

读取文件,写入命名管道


读取管道,写入目标文件

结果如下:



命名管道实现原理

因为所有的进程通信方式,其本质上就是让不同的进程看到一份公共资源,而命名管道就是通过创建管道文件,让不同进程都打开这个相同的管道文件,这样它们就可以看到一份公共资源,这就实现了进程间通信的目的

命名管道和匿名管道的区别

  1. 匿名管道由pipe函数创建并打开,命名管道由mkfifo函数创建,由open打开
  2. 匿名管道只能在具有亲缘关系进程间通信,而命名管道可以应用于不相关的进程间通信
  3. 命名管道是一种特殊类型的文件
  4. 匿名管道在硬盘上没有对应文件,而命名管道在硬盘上有对应文件


猜你喜欢

转载自blog.csdn.net/lw__sunshine/article/details/80843354