管道与共享内存 区分
转载自:https://blog.csdn.net/ifwecande/article/details/107470579
管道
操作系统分为内核态和用户态,管道就是在内核中开辟一块缓冲区,不同的进程通过对这个缓冲取进行读写操作实现IPC。
管道其实有三种不同的形式,
- 匿名管道,半双工通信,只能在父子或者兄弟进程间使用.,
- 命令流管道s_pipe: 全双工。父子兄弟间使用。
- 命名管道FIFO:半双工通信。任意进程间使用。
下面对匿名管道和命名管道进行详细介绍。
匿名管道
匿名管道是在内核中开辟一块缓冲区,而这块缓冲取没有具体的标识符,因此只能用于具有亲缘关系的进程间通信。
子进程可以通过复制父进程获得这块缓冲取(管道)的操作句柄,因为父进程创建管道的时候会接收到管道的操作句柄(文件描述符)。
这也是linux下一切皆文件的一种体现。
使用pipe函数进行创建:
int pipe(
由参数fd返回两个文件描述符,fd[0]为读而打开 fd[1]为写而打开
通过这两个读写的端口就轻松实现了同步与互斥。
关于匿名管道需要注意的是管道的读写特性:
- 管道无数据,调用read阻塞
- 管道数据满了,调用write阻塞
- 管道所有读端被关闭,继续调用写会导致异常进程退出
- 管道所有写端被关闭,继续调用读,当读完管道中数据的时候,会返回0
命名管道
命名管道也是内核中的一块缓冲区,但是这块缓冲区有具体的标识符,不同进程可以通过标识符来对管道进行操作,从而达到通信的目的。
可以通过命令 mkfifo创建管道文件。
也可以通过代码 int mkfifo(char* filename , mode_t mode)
参数一是管道文件名,参数二是创建文件的一些权限,与IO操作类似
成功返回0,失败返回-1.
注意:当我们通过open打开这个命名管道时,
- 若文件以只读方式打开则会阻塞直到以只写方式打开。
- 若文件以只写方式打卡则会阻塞直到以只读方式打卡。
总结管道特性。
- 管道是半双工通信
- 匿名读写特性与命名管道的打开特性。
- 生命周期随进程(当没有手动释放时)
- 管道提供字节传输服务 – 可靠,有序,基于连接的传输服务。
- 自带同步与互斥。
同步:通过条件判断实现对临界资源操作的合理性。
互斥:通过唯一访问实现对临界资源操作的安全性。
共享内存
共享内存的最大特性: 最快的进程间通信方式。
共享内存的本质是直接在物理空间上开辟的一块物理内存,而非pcb的虚拟内存,多个进程可以将自己的虚拟地址映射到这块内存上面从而达到通信的目的,相比于其他方式,很明显,这种方式有效的降低了输入输出数据的拷贝次数,从而降低了效率。
映射方式如图: 中间是共享内存,两边分别是不同的进程通过页表映射。
共享内存的操作流程:
- 创建共享内存 – 在物理内存上开辟空间。
- 进程将自己的共享内存映射到自己的虚拟地址空间。
- 进行基本的IO操作
- 操作完毕,接触映射关系
- 释放内存空间。
共享内存没有同步与互斥,因此需要用户手动去添加。否则多进程访问时可能会出现安全问题。