Linux 进程间通信详解

123 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情

每个进程的用户地址空间都是独立的,一般而言是不能互相访问的,但内核空间是每个进程都共享的,所以进程之间要通信必须通过内核,几种常见的进程间通信方式如下:

  • 无名管道
  • 有名管道
  • 消息队列
  • 共享内存
  • 信号量
  • 信号
  • 套接字

1. 无名管道

Linux中最常用的|命令就是我们所说的无名管道。

A | B

无名管道创建的文件是特殊的文件,只存在于内存,不存于文件系统中。其实,所谓的管道,就是内核里面的一串缓存。从管道的一端写入的数据,储存在内核中,由另一端读取。

当我们的父进程执行A | B的shell命令时,后创建两个子进程,并且进行连通:

image.png

对于匿名管道,它的通信范围是存在父子关系的进程。因为管道没有实体,也就是没有管道文件,只能通过 fork 来复制父进程 fd 文件描述符,来达到通信的目的。

2. 有名管道

有名管道在使用上很像Go中的channl。

mkfifo myPipe // 创建管道

echo "hello" > myPipe // 将数据写进管道

cat < myPipe  // 读取管道里的数据

有名管道创建了一个类型为管道的设备文件,在进程里只要使用这个设备文件,就可以相互通信,它可以在不相关的进程间也能相互通信

不管是匿名管道还是命名管道,进程写入的数据都是缓存在内核中,另一个进程读取数据时候自然也是从内核中获取。

3. 消息队列

消息队列是保存在内核中的消息链表,在发送数据时,会分成一个一个独立的数据单元,消息的发送方和接收方要约定好消息体的数据类型(不适合比较大数据的传输),所以每个消息体都是固定大小的存储块,不像管道是无格式的字节流数据。如果进程从消息队列中读取了消息体,内核就会把这个消息体删除。

消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销,因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程,同理另一进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。

4. 共享内存

共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中,另外,共享内存省去了用户态与内核态之间消息拷贝的过程。