进程间通信(IPC)
进程间通信:操作系统为用户提供的用于实现进程之间进行通信的方式
进程之间是无法直接通信的:因为每个进程都有独立的虚拟地址空间,访问的都是自己的虚拟地址,因此进程具有独立性,无法直接通信。
进程间通信方式种类:
管道 | 共享内存 |
消息队列 | 信号量 |
管道
本质:在内核中开辟的一块缓冲区(内核空间中的一块内存)
原理:多个进程通过访问同一块内核中的缓冲区实现通信
特性 | |
---|---|
通信方式 | 半双工通信 |
读取特性 | 若管道中没有数据,则read会阻塞;若管道中数据已满,则write会阻塞。 |
所有的管道读端被关闭,继续write则会触发异常导致进程崩溃退出 | |
所有的管道写端被关闭,继续read则会读完数据后返回0,不再阻塞。 | |
提供字节流传输服务 | 有序的、可靠的、基于连接的流式传输 |
基于连接 | 所有读端关闭则write异常;所有写端关闭则read异常 |
自带同步与互斥 | 互斥:通过同一时间进程对【临界资源】的唯一访问实现访问操作安全,体现在对管道进行写入操作时,写入大小不超过PIPE_BUF-4096大小则保证操作的原子性 |
同步:通过一些条件判断让进程对临界资源的访问更加合理有序,体现在基于连接特性上 | |
生命周期随进程 | 不人为干预情况下,则所有打开管道的进程退出后,管道缓冲区被释放 |
补充解释 | 【临界区】:对临界资源访问的这段代码区域 |
【临界资源】:公共资源,大家都能访问到的资源 |
分类 | 特点 |
---|---|
匿名管道 | 缓冲区没有标识符,只能用于具有亲缘关系的进程间通信 |
命名管道 | 缓冲区具有标识符,可用于同一主机上任意的进程间通信 |
匿名管道:
int pipe(int pipefd[2])
pipefd[0]:用于读
pipefd[1]:用于写
返回值:成功返回0,失败返回-1
序号 | 特性 |
---|---|
1 | 只能用于具有亲缘关系的进程间通信 |
2 | 匿名管道没有标识符,无法被其他进程找到,只能通过子进程复制父进程的方式获取到操作句柄实现通信 |
管道符:|
连接两个命令,将前边命令的打印结果传输给后边的命令进行处理
管道符的实现就是通过匿名管道实现的。
命名管道
本质:内核中的一块缓冲区,具有标识符,可以被其他进程找到,因此可以用于同一主机上的任意进程间通信。
命名管道的标识符就是一个可见于文件系统的管道类型文件
多个进程通过打开同一个管道文件,访问同一块内核中的缓冲区实现通信
命令操作:mkfifo filename
创建一个命名管道文件
函数操作:
int mkfifo(const char* pathname,mode_t mode)
pathname:文件名 mode_t:权限
成功返回0,失败返回-1;
打开特性:
1.若以只读方式打开管道文件则会阻塞,直到管道被其他进程以写的方式打开;
2.若以只写方式打开管道文件则会阻塞,直到管道被其他进程以读的方式打开。
共享内存
用于实现进程间的数据共享
本质:一块物理内存
原理:开辟一块物理内存空间,多个进程将同一块映射到自己的虚拟地址空间直接进行访问进而实现数据共享
特性:最快的进程间通信方式,生命周期随内核
共享内存通过虚拟地址直接访问物理内存实现数据共享,相较于其他方式需要将数据拷贝到内核,使用时拷贝到用户态,少了两次数据拷贝操作
步骤 | 操作流程 |
---|---|
1 | 创建或打开共享内存 |
2 | 将共享内存映射到进程的虚拟地址空间 |
3 | 通过映射的虚拟地址进行各种内存操作 |
4 | 解除映射关系打开 |
5 | 删除共享内存 |
函数接口:
int shmget(key_t key,size_t size,int shmflg);
key:标识符—多个进程通过相同的标识符打开同一块共享内存
size:创建时所开辟空间大小(以内存页为单位)
shmflg:打开方式+创建权限—IPC_CREAR | IPC_EXCL | 0664
返回值:成功返回非负整数(操作句柄),失败-1
void *shmat(int shmid,const void *shmaddr,int shmflg);
shmid:shmget返回的操作句柄
shmaddr:映射地址——通常置空
shmflg:映射成功后的访问方式;SHM_RDONLY-只读;0-读写
返回值:成功返回映射后的首地址,失败(void*)-1
int shmdt(const void* shmaddr);解除映射关系
shmaddr:映射后的首地址
返回值:成功返回0,失败-1
int shmctl(int shmid,int cmd,struct shmid ds *buf)
shmid:shmget返回的操作句柄
cmd:操作类型——IPC_RMID——标记共享内存为被销毁
buf:用预设值或者获取共享信息,不使用置空即可
返回值:成功0,失败-1
注意事项:共享内存是临界资源,对共享内存的操作需要注意安全问题