进程通信
进程通信就是进程间信息交换,
由于进程是分配系统资源的单位,因此各进程拥有的内存地址空间相互独立,为保证安全,一个进程不能直接访问另一个进程的地址空间,因此需要通过其他方法实现进程通信
共享存储
设置共享空间,互斥访问,即一次只能有一个进程进行读写操作,操作系统提供共享空间和同步互斥工具
共享存储有两种
基于数据结构的共享
共享空间里面只能放一个长度为10的数组,这样共享速度慢,限制多,低级
基于存储区的共享
在内存中画出一块共享存储区,数据的形式和存放位置都由进程控制,而不是操作系统。相比上面,显然这个更高级
管道通信
分为无名管道pipe和有名管道FIFO
pipe
无名管道一般用于两个不同进程之间的通信,但只能在具有亲缘关系的进程间使用
而有名管道允许无亲缘关系进程间通信
FIFO
FIFO可设置阻塞标志O_NONBLOCK
通常情况下,没标志的情况下,为读而打开FIFO时,需要已经有进程已经为写而打开FIFO,才能成功返回,反过来亦然,只读open则立即返回,只写则返回ENXIO错误
当设置标志时,一直阻塞
从FIFO读取数据
当一个进程为了从FIFO读取数据而阻塞打开FIFO,则称为该进程的读操作为设置了阻塞标志的读操作。
对于设置阻塞标志的读操作来说,造成阻塞只有两种情况,
FIFO内有数据,但其他进程在读
FIFO内没有数据,返回-1,errno设为EAGAIN
读打开的阻塞标志只对本进程第一个读操作施加作用,后续读操作不再阻塞,当FIFO没有数据时则返回0
从FIFO写入数据
当一个进程为了向FIFO中写入数据而阻塞打开FIFO,那么称该进程内的写操作为设置了阻塞标志的写操作
-
当设置了阻塞标志时
当写入的数据量小于等于PIPE_BUF时,linux保证写入的原子性,若此时管道空闲区不足要容纳的字节数,则进入睡眠,直到当缓冲区能够容纳要写入的字节数时才进行一次性写操作。
当写入的数据量大于PIPE_BUF时,linux不再保证写入的原子性,FIFO缓冲区一有空闲区域,就试图写入数据到管道中,写完所有数据后返回 -
当没有设置阻塞标志时,linux不保证写入的原子性
当写入的数据大于PIPE_BUF时,写满才返回
当写入数据不大于PIPE_BUF时,若空闲区满足则写入返回,不满足则返回EAGAIN错误
特征
- 管道是用于连续读写进程的一个共享文件,又名pipe文件,其实就是开辟大小固定的缓冲区
- 管段采用半双工通信,同一时间段内只能单向传输,如果要实现双向同时通信,需要设置两个管道
- 管道也是互斥访问的
- 数据以无格式字符流形式写入管道,当管道写满时,写进程write系统调用被阻塞,等待读进程将数据取走
- 当读进程将数据取走后,管道变空,read()堵塞
- 如果没写满,不允许读,没读空,不允许写
- 数据一旦被读出,就从管道中被抛弃,意味着读进程只能有一个
消息传递
发送消息的进程将消息头写好,接受信息进程根据消息头读取信息或者寻找信封是哪一个。
进程间数据交互以格式化的消息为单位,进程通过系统提供 发送/接受消息两个原语进行数据交换
消息结构为:消息头和消息体
消息头包含:发送进程ID、接受进程ID、消息类型、消息长度等
消息传递有两种方式
直接通信方式和间接通信方式
直接通信方式:消息直接挂到接收进程的消息缓冲队列上
间接通信方式:消息要先发送到中间实体中
优劣比较
管道:速度慢,容量有限,只允许父子进程通信
FIFO:任何进程都能通信,但慢
消息队列:信息复制消耗cpu时间,不适宜信息量大或者操作频繁的场合,容量受限制,则第一次读时要考虑上一次有没有读完数据的问题,但无需考虑同步问题
信号量:不能传递复杂消息,只能用来同步
共享内存区:容易控制容量,速度快,但需要额外保证同步,且不适用于多个计算机间通信