管道:
System V IPC:
POSIX IPC:
管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
管道的特征:
管道也有其局限性:
#include
//功能:创建一无名管道
//原型
int pipe(int fd[2]);
//参数
//fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
//返回值:成功返回0,失败返回错误代码
匿名管道创建完成,如何通信呢?
读取管道数据时:
若管道中有数据,read返回实际读取到的字节数。
若管道中无数据,当写端被关闭,read返回0,当写端没有被关闭,read阻塞等待。
向管道写入数据时:
若管道读端关闭,进程异常终止
读端未关闭,若管道未满,返回实际写入字节数,若管道已满,write阻塞等待。
匿名管道特点:
匿名管道的局限是只能在有血缘关系的进程之间进行通信,如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。命名管道是一种特殊类型的文件。
FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存储于文件系统中。命名管道是一个设备文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。值得注意的是,FIFO(first input first output)总是按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出。
命名管道可以从命令行上创建,命令行方法是使用下面这个命令:
mkfifo filename
命名管道也可以从程序里创建,相关函数有:
int mkfifo(const char* filename, mode_t mode);
//mode代表权限
共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。
在Linux中,每个进程都有属于自己的进程控制块(PCB)和进程地址空间(Addr Space),并且都有一个与之对应的页表,负责将进程的虚拟地址与物理地址进行映射,通过内存管理单元(MMU)进行管理。两个不同的虚拟地址通过页表映射到物理空间的同一区域,它们所指向的这块区域即共享内存。
共享内存原理示意图:

使用共享内存的步骤:
注意:共享内存没有同步和互斥机制
**消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。**消息队列是消息的链接表,存放在内核中并由消息队列标识符标识。
每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题(命名管道要读端和写端都存在,否则出现阻塞)。
消息队列与命名管道一样,每个数据块都有一个最大长度的限制。
为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。
临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就是说信号量是用来调协进程对共享资源的访问的。
由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行。此步骤申请信号量
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1。此步骤释放信号量