一、共享内存
1、原理
之前的管道方式是基于文件系统来实现的进程间通信,儿共享内存是在内存中开辟一段空间供进程通信,本质不同。
2、细节
(1)上述操作都是操作系统做的。
(2)操作系统一定会提供1,2步的系统调用供进程使用。
(3)共享内存存在多份,供不同对进程使用
(4)所以共享内存先描述再组织,struct shm
(5)共享内存 = 共享空间(数据)+ 共享内存属性
3、实现
(1)函数介绍
int shmget(key_t key, size_t size, int shmflg) 创建共享内存
key:用户设置,具有唯一性,让进程找到同一份共享内存。
size:内存大小。
shmflg:标记位
IPC_CREAT:如果共享内存不存在就创建,存在就获取后返回。(获取已经创建的共享内存User)
IPC_EXCL:单独使用无意义。
IPC_CREAT | IPC_EXCL:如果共享内存不存在就创建,存在就出错返回。(创建一个新的共享内存Creater)
返回值:共享内存标识符shmid
key_t ftok(const char* pathname, int proj_id) 获取key
pathname:共享内存路径
proj_id:设置id用于创建唯一key
int shmctl(int shmid, int cmd, struct shmid_ds* buf) 控制共享内存
cmd:IPC_RNID命令用于删除共享内存。
ipcs -m 查看共享内存
ipcrm -m shmid 删除共享内存
(2)对比key,shmid
key是用户创建,内核使用,用来区分shm唯一性,用户无法使用。
shmid是共享内存标识符,用来用户级内存管理的id值。
所以删除共享内存用的是shmid
(3)实现
(4)挂接与取消挂接共享内存
上述代码只是申请了共享内存,我们需要挂接共享内存进行使用。
void* shmat(int shmid, const void* shmaddr, int shmflg) 挂接共享内存
shmaddr:挂接位置
shmflg:共享内存权限
失败返回nullptr,成功返回起始地址,相当于malloc返回值。
int shmdt(const void* shmaddr) 取消挂接共享内存
shmaddr:函数shmat()返回值
(5)实现
二、消息队列
1、原理
一个进程向另一个进程发送有类型的数据块。
2、函数
(1)获取消息队列
int msgget(key_t key, int magflg)
(2)获取key
key_t ftok(const char* pathname, int proj_id)
(3)删除
int msgctl(int msgid, int cmd, struct msqid_ds* buf)
buf:输出型参数,返回消息队列具体信息
(4)发消息
int msgsnd(int msqid, const void* msgp, size_t msgsz, int msflg)
(5)查看
ipcs -q
(6)删除
ipcs -q msqid
三、信号量
1、基础知识
(1)共享资源:多执行流(进程)能看到的一份资源
(2)互斥:任何时候只有一个进程访问共享资源
(3)临界资源:被保护起来的资源,互斥可以保护
(4)程序员通过代码访问资源,代码 = 访问共享资源代码 + 不访问共享资源代码
2、信号量理解
信号量是用来保护临界资源,本质是一个计数器进行加减,当变成0时,进程就要等待。
信号量和共享内存,消息队列一样,必须让不同进程看到同一个计数器,意味着信号量也是一个共享资源,所以信号量的 -- 操作(P)和 ++ 操作(V)必须时安全的,原子的。
四、总结
操作系统如何把共享内存,消息队列,信号量管理起来?