目录
共享内存
原理
两个进程的PCB各自维护着一个进程地址空间。当两个进程要进行通信时:
- 操作系统在内存中开辟一个内存块。
- 通过两个进程的页表,将内存中的内存块映射到两个进程的进程地址空间中。
- 此时两个进程就能看到同一个内存了,也就建立了通信。
- 进行通信时,两个进程只需要访问自己的进程地址空间即可,操作系统会通过页表访问内存中的内存块。
实践
shmget() 创建共享内存
- 功能:
在内存中创建共享内存
- 参数:
- key_t key 用来确定共享内存的唯一标识(系统中有很多共享内存,如何确定进程A和进程B通信的共享内存是同一个呢?通过key来确定)
- size_t size 创建共享内存的大小
- int shmflg 共享内存的权限,包括下面两种:
1、 IPC_CREAT 不存在创建,存在获取
2、IPC_EXCL 无法单独使用,必须与其他标志组合使用
IPC_CREAT | IPC_EXCL:创建共享内存,如果不存在,则创建,如果存在,错误返回。
- 返回值
创建成功返回共享内存的标识,失败返回-1。
如何获取key?
- 功能
创建独一无二的key值
- 参数
1、pathname: 文件的路径,可以随便填写,建议当前路径"./"
2、proj_id:项目的id,可以随便填写
- 返回值
返回一个key值
shmctl() 删除共享内存
当我们在进程通信时使用shmget创建了共享内存,但是当进程结束之后,共享内存并没有消失。
共享内存的生命周期是随内核的,用户不主动关闭,就一直存在。
可以使用 ipcs -m 指令查看共享内存.
如何删除共享内存? 两种方式:
1、手动输入命令 ipcrm -m shmid 删除
2、在程序中使用函数 shmctl()删除
- 功能
删除指定shmid的共享内存
- 参数
1、shmid 要删除的共享内存的id,是shmget的返回值
2、cmd 删除的命令,常用的是IPC_RMID,也有时候用IPC_STAT
3、buf 描述共享内存的数据结构的指针,一般设置为nullptr
- 返回值
成功返回 0, 失败返回 -1
shmat() 挂接进程和共享内存
- 功能
使两个进程挂接到同一个共享内存上
- 参数
1、shmid 创建共享内存后返回的标识符,shmget的返回值
2、shmaddr 指定共享内存映射到进程地址空间中的地址,一般设置成NULL,让系统自动来设置。
3、shmflg 权限,可以设置为0
- 返回值
共享内存映射到进程地址空间中的地址(shmaddr),不成功返回-1
shmt() 进程和共享内存去关联
- 功能
将进程和共享内存去关联
- 参数
shmaddr 指定共享内存映射到进程地址空间中的地址,shmat的返回值。
- 返回值
返回挂接进程个数
共享内存的特性
优势
当使用管道进行进程间通信的时候,需要拷贝4次。
键盘->写入端进程地址空间->管道->写出端进程地址空间->显示器
使用共享内存进行进程间通信的时候,需要拷贝两次
键盘->共享内存(写入写出端进程地址空间)->显示器
所以,共享内存是进程间通信最快的!
劣势
共享内存通信方式没有同步和互斥机制,容易导致混乱。
用共享内存实现进程间通信
实现进程间通信,需要两个进程,一个做客户端,一个做服务端
运行结果: