共享内存有点像动态库
创建共享内存:操作系统在物理内存分配一段空间(Shared Memory Segment)
将共享内存挂起:通过页表将共享内存映射到两个进程的共享区
通信:拿到虚拟地址,写端直接在地址上写数据,读端直接在地址上读数据
断开挂起,销毁共享内存

和文件一样,共享内存也会有对应的内核结构体来描述,有对应的共享内存描述符。


ftok是一个算法函数,目的是通过路径名和proj_id的计算,获取到一个共享内存的唯一标识key值
ftok不能保证获取的key值和已经存在的共享内存不同,如果出现冲突,需要对参数做适当修改,


shmget可以通过key值创建/找到共享内存
size表示共享内存的大小,size大小尽量是内存块大小(4KB)的整数倍
shmflg是一个比特标志位的参数:
IPC_CREAT表示没有key对应的共享内存就创建,存在不创建
IPC_EXCL不单独使用,必须和IPC_CREAT一起用,表示如果已经存在对应的key所对应的共享内存就报错退出
mode,表示文件权限
shmid(共享内存描述符)和key都是共享内存的标识,二者有何区别?
key是操作系统层面的标识唯一性的值,而shmid是在进程层面标识唯一性的值

一般情况下,shmaddr传nullptr,shmflg传0就可以了。返回的void*指针需要类型转换后使用


这个函数的功能很多,介绍两种用法:
cmd是一个比特标志位的参数,可传参有很多。buf是一个输入型参数,它是一个结构体,结构体有很多共享内存的属性
cmd传IPC_RMID表示要销毁共享内存,buf直接传nullptr即可
cmd传IPC_STAT,buf传一个提前创建好的struct shmid_ds结构体指针即可,后面可以对buf结构体内容进行访问

共享内存销毁并不是直接销毁,操作系统会通过共享内存结构体的引用计数判断,只有当引用计数为0,才会真正销毁。否则本质都是让引用计数减1
1.共享内存的生命周期是随内核的,用户不主动关闭,内存会一直存在,除非内核重启。
可以在进程使用结束后关闭,如果未能正常关闭:
使用ipcs -m查看当前所有内存块信息
ipcrm -m [shmid] 关闭内存
2.共享内存没有同步互斥类似的保护数据的机制,数据由用户维护
3.共享内存是所有进程通信中,速度最快的
- //comm.hpp 包含客户端和服务端的头文件
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- //sever.cpp 服务端创建共享内存,读
- #include "comm.hpp"
- using namespace std;
- int main()
- {
- //Log log;
- // 创建共享内存
- key_t k = ftok("/home/ly/brilliant-alone/Linuxcode/IPC", 0x6666);
- int shmid = shmget(k,4096, IPC_CREAT|IPC_EXCL|0666);
- if(shmid < 0)
- {
- //cout << "shmget fail" << endl;
- cout << strerror(errno) << endl;
- return -1;
- }
- //挂到进程地址空间
- char* add = (char*)shmat(shmid, nullptr, 0);
- //读取
- while(1)
- {
- cout << "client say:" << add <
- sleep(1);
- }
-
- //断开挂起
- shmdt(add);
- //关闭
- shmctl(shmid, IPC_RMID, nullptr);
- return 0;
- }
-
- //client.cpp 客户端 写
- #include "comm.hpp"
- using namespace std;
-
- int main()
- {
- // 找shmid
- key_t k = ftok("/home/ly/brilliant-alone/Linuxcode/IPC", 0x6666);
- int shmid = shmget(k, 4096, IPC_CREAT);
- // 挂到进程地址空间
- char* add = (char*)shmat(shmid,nullptr,0);
- //写入
- while(1)
- {
- cout << "Input:";
- fgets(add, 4096, stdin);
- }
- shmdt(add);
- return 0;
- }