管道
匿名管道
将前一个命令的输出,作为后一个命令的输入
我们可以得知,对于匿名管道,它的通信范围是存在父子关系的进程。因为管道没有实体,也就是没有管道文件,只能通过 fork 来复制父进程 fd 文件描述符,来达到通信的目的。
命名管道
也被叫做 FIFO
,因为数据是先进先出的传输方式。
在使用命名管道前,先需要通过 mkfifo
命令来创建,并且指定管道名字:
shell
复制代码
$ mkfifo myPipe
另外,对于命名管道,它可以在不相关的进程间也能相互通信。因为命令管道,提前创建了一个类型为管道的设备文件,在进程里只要使用这个设备文件,就可以相互通信。
管道这种通信方式效率低,不适合进程间频繁地交换数据。当然,它的好处,自然就是简单,同时也我们很容易得知管道里的数据已经被另一个进程读取了。 不管是匿名管道还是命名管道,进程写入的数据都是缓存在内核中,另一个进程读取数据时候自然也是从内核中获取,同时通信数据都遵循先进先出原则。
消息队列
- 消息队列是保存在内核中的消息链表
- 消息队列的通信模式:生产者将数据放入队列,及完成;消费者取出,完成。不像管道是无格式的字节流数据。如果进程从消息队列中读取了消息体,内核就会把这个消息体删除。
- 消息队列生命周期随内核,如果没有释放消息队列或者没有关闭操作系统,消息队列会一直存在,而前面提到的匿名管道的生命周期,是随进程的创建而建立,随进程的结束而销毁。
- 克服了管道通信的数据是无格式的字节流的问题
- 缺点:
- 通信不及时
- 附件也有大小限制
- 存在用户态与内核态之间的数据拷贝开销
共享内存
共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。这样这个进程写入的东西,另外一个进程马上就能看到了
信号量
信号量其实是一个整型的计数器,主要用于实现进程间的互斥与同步,而不是用于缓存进程间通信的数据。
控制信号量的方式有两种原子操作。P 操作和 V 操作
信号初始化为 1
,就代表着是互斥信号量,它可以保证共享内存在任何时刻只有一个进程在访问,这就很好的保护了共享内存。
信号初始化为 0
,就代表着是同步信号量,它可以保证进程 A 应在进程 B 之前执行。
信号
信号跟信号量,两者用途完全不一样!
对于异常情况下的工作模式,就需要用「信号」的方式来通知进程。
比如
Ctrl+C
产生SIGINT
信号,表示终止该进程;Ctrl+Z
产生SIGTSTP
信号,表示停止该进程,但还未结束;kill -9 <PID>
,杀死<PID>
号进程 所以,信号事件的来源主要有硬件来源(如键盘 Cltr+C )和软件来源(如 kill 命令)。
信号是进程间通信机制中唯一的异步通信机制,因为可以在任何时候发送信号给某一进程。
Socket
跨网络与不同主机上的进程之间通信
线程间通信
同个进程下的线程之间都是共享进程的资源,只要是共享变量都可以做到线程间通信,比如全局变量。
所以对于线程间关注的不是通信方式,而是关注多线程竞争共享资源的问题,信号量也同样可以在线程间实现互斥与同步:
- 互斥的方式,可保证任意时刻只有一个线程访问共享资源;
- 同步的方式,可保证线程 A 应在线程 B 之前执行;