携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情
每个进程的用户地址空间都是独立的,一般而言是不能互相访问的,但内核空间是每个进程都共享的,所以进程之间要通信必须通过内核,几种常见的进程间通信方式如下:
- 无名管道
- 有名管道
- 消息队列
- 共享内存
- 信号量
- 信号
- 套接字
1. 无名管道
Linux中最常用的|命令就是我们所说的无名管道。
A | B
无名管道创建的文件是特殊的文件,只存在于内存,不存于文件系统中。其实,所谓的管道,就是内核里面的一串缓存。从管道的一端写入的数据,储存在内核中,由另一端读取。
当我们的父进程执行A | B的shell命令时,后创建两个子进程,并且进行连通:
对于匿名管道,它的通信范围是存在父子关系的进程。因为管道没有实体,也就是没有管道文件,只能通过 fork 来复制父进程 fd 文件描述符,来达到通信的目的。
2. 有名管道
有名管道在使用上很像Go中的channl。
mkfifo myPipe // 创建管道
echo "hello" > myPipe // 将数据写进管道
cat < myPipe // 读取管道里的数据
有名管道创建了一个类型为管道的设备文件,在进程里只要使用这个设备文件,就可以相互通信,它可以在不相关的进程间也能相互通信。
不管是匿名管道还是命名管道,进程写入的数据都是缓存在内核中,另一个进程读取数据时候自然也是从内核中获取。
3. 消息队列
消息队列是保存在内核中的消息链表,在发送数据时,会分成一个一个独立的数据单元,消息的发送方和接收方要约定好消息体的数据类型(不适合比较大数据的传输),所以每个消息体都是固定大小的存储块,不像管道是无格式的字节流数据。如果进程从消息队列中读取了消息体,内核就会把这个消息体删除。
消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销,因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程,同理另一进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。
4. 共享内存
共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中,另外,共享内存省去了用户态与内核态之间消息拷贝的过程。