进程间通信
1.进程间通信:进程间的数据交换
2.操作系统为上层提供进程间通信方式
原因:进程具有独立性,每个进程都访问的是自己的虚拟地址空间中的虚拟地址,因此需要操作系统提供一个进程间都可以访问的区域来实现通信。应用场景不同,因此提供的方式也多种多样
3.四种方式:管道 共享内存 消息队列 信号量
一.管道
1.管道:用于实现进程间的数据传输功能
2.本质原理:
管道是内核中的一块缓冲区,多个进程通过访问同一缓冲区实现通信
3.种类:匿名管道和命名管道
匿名管道:内核中的缓冲区没有标识,只能用于具有亲缘关系的进程间通信
命名管道:内核中的缓冲区具有标识,因此可以用于同一主机上的任意进程间通信
匿名管道:
int pipe(int pipefd[2]);
pipefd[2]:拥有两个整型元素的数组,用于接收管道的操作句柄
pipefd[0]:用于从管道中读取数据
pipefd[1]:用于向管道中写入数据
返回值:成功返回0;失败返回-1
管道的特性:半双工通信 自带同步与互斥 提供字节流服务 生命周期随进程
1.管道是半双工通信
2.管道自带同步与互斥
互斥:管道的写操作在不超过PIPE_BUF大小(4096)字节,保证原子性------用于保证安全操作
同步:让资源的访问操作按照某种规则有序进行,避免产生饥饿问题--------用于保证合理操作
若管道中没有数据,则read会阻塞;缓冲区若数据满了,则write会阻塞
3.管道提供字节流服务:有序的,可靠的,不限制大小的,基于连接的
基于连接的:有读必须有写,有写必须有读
若所有读端被关闭,则继续写入会触发异常,导致进程退出;若所有写端关闭,则读完数据之后不再阻塞,而是返回0
4.管道的生命周期随进程:在不人为干预的情况下,所有打开管道的进程退出后,管道被释放
|—管道符:连接两个命令,将前边的命令的输出结果交给后边的命令作为输入进行处理
命名管道
1.命名管道;内核中的缓冲区具有标识,因此可以用于同一主机上的任意进程间通信
2.本质:内核中的缓冲区,只是标识符是可见于文件系统的管道文件
多个进程通过打开同一个管道文件,访问到同一个缓冲区实现通信
.管道的本质没有改变,因此缓冲区的大小,不受磁盘空间影响
int mkfifo(const char*pathname,mode_t mode);
pathname:管道标识符文件的名称
mode:文件权限
返回值:成功返回0;失败返回-1
3.命名管道的打开特性:
如果命名管道没有被写的方式打开,则只读打开会阻塞
如果命名管道没有被读的方式打开,则只写打开会阻塞
二.共享内存
1.本质:
开辟一块内存空间,多个进程通过将同一块物理内存映射到自己的虚拟地址空间,通过自己的虚拟地址进行访问,实现数据共享
2.特性:共享内存是最快的进程间通信方式,生命周期随内核
共享内存的操作相较于其他操作少了两部用户态与内核态之间的数据交换
3.注意事项:
共享内存的操作并非是安全的,有可能多个进程写入会造成数据交叉或覆盖
共享内存的操作时需要保护的(通过同步与互斥进行保护)
4…操作流程:
a.创建或打开共享内存
int shmget(key_t key,size_t size,int shmfllg);
key:共享内存的标识符—多个进程通过相同的标识符打开同意共享内存
size:共享内存大小
shmflg:操作方式-IPC_CREAT|EXCL;操作权限:0664
返回值:成功返回非负整数–共享内存在代码中的操作句柄;失败返回-1
b.将这块共享内存映射到进程的虚拟地址空间
void* shmat(int shmid,const void*shmaddr,int shmflg);
shmid:shmget返回的操作句柄;
shmaddr:虚拟地址空间中的映射首地址—NULL
shmflg:SHM_RDONLY-只读/否则默认0–表示可读可写
返回值:成功返回实际映射在虚拟地址空间的首地址;失败返回(void*)-1;
c.内存操作
d.解除进程与共享内存的映射关系
int shmdt(const void* shmaddr);
shmaddr:虚拟地址空间中的映射首地址; 返回值:成功返回0,失败返回-1;
e.删除共享内存
每个共享内存都有一个映射连接数(标识当前有多少进程与自己建立了映射连接),因此删除共享内存,共享内存只有在映射连接数为0的时候才会被删除,如果当前不为0,则从当前开始拒绝后续的映射连接请求,直到映射连接数为0
int shmct(int shmid,int cmd,struct shmid_ds*buf);
shmid:操作句柄;
cmd:具体对共享内存要进行操作----IPC_RMID删除
buf:主要用于设置或者获取共享内存的信息,这里直接设置NULL即可
返回值:对于IPC_RMID操作来说,成功返回0,失败返回-1;
三.消息队列
1.本质原理:指针内核中创建了一个优先级队列;多个进程可以通过相同的标识符找到内核中同一个消息队列,通过添加或者获取节点实现数据传输
2.特性:自带同步与互斥 生命周期随内核
四.信号量
1.本质:一个计数器(对资源进行计数)
2.功能:用于实现进程间的同步与互斥
同步:实现临界资源访问的合理性
信号量对数据资源进行计数,所有的进程在访问资源之前,先访问信号量,如果还有资源,则流程继续,获取一个资源,计数-1;等到计数<=时,进程想要获取资源则需要等待(将进程状态设置为阻塞状态,陷入休眠),等待资源计数>0(产生一个资源计数就会+1),则唤醒进程的等待(将进程的状态置为运行状态,开始调度)
信号量的操作:
P操作:在临界资源获取之前,先进行P操作,判断能否获取(能获取-1,不能等待)
V操作:在资源产生之后,进行V操作(计数+1,唤醒一个等待中的进程)
信号量实现互斥:同一个时间只有一个进程能够访问资源,保证临界资源访问的安全性
实现互斥的原理,就是总认为资源只有一个,计数最大为一,一个进程在访问之前,访问信号量,P操作数-1,为0(其他进程访问就会被阻塞);等到这个进程访问完毕之后,再进行V操作,计数+1
ipcs 查看进程间通信资源/ipcrm 删除进程间通信资源
-m 针对共享内存的操作
-q 针对消息队列的操作
-s 针对消息队列的操作
-a 针对所有资源的操作