目录
1 共享内存的原理
- 在物理内存中开辟一段空间
- 不同的进程通过页表将物理内存空间映射到自己的进程虚拟地址空间当中
- 不同的进程通过操作自己进程虚拟地址空间当中的虚拟地址,来操作共享内存
共享内存的接口
- 1.1创建或者获取共享内存的接口
- int shmget(key_t key,size_t size,int shmflg);
- 参数:
- key:共享内存标识符,
- size :共享内存的大小
- shmflg:获取或创建共享内存时,传递的属性信息
- IPC_CREAT:如果获取的共享内存不存在,则创建
- IPC_EXCL | IPC_CREAT:如果获取的共享内存存在,则函数报错,如果获取共享内存不存在,则创建。换句话说:该组合要获取的是重新创建共享内存。
- 按位或上权限,权限也是八进制数字,权限是指给创建出来的共享内存约定的权限
- 返回值:成功:返回共享内存操作句柄;失败:返回-1
- 参数:
- 1.2 将共享内存附加到进程的虚拟地址空间.
- 通过附加,让物理内存中的共享区域和进程虚拟地址空间中的共享区建立映射关系
- void *shmat(int shmid, const void *shmaddr,int shmflg) ; .
- 参数:
- shmid:共享内存操作句柄(shmflg的返回值)
- shmaddr:将共享内存附加到共享区当中的哪一个地址上。一般让操作系统自己分配(因为用户不知道共享区的哪一块空间被使用了,所以让操作系统去分配),传递NULL
- shmflg:以什么权限将共享内存附加到进程当中,这里的权限是指约束进程对共享内存有什么样的权限;
- SHM_ RDONLY: 只读
- 0 : 可读可写
- 返回值:
- 成功:返回附加的虚拟地址
- 失败:NULL
- 代码验证:
-
#include <stdio.h> #include <unistd.h> #include <sys/shm.h> int main(){ //1.获取共享内存 int shm_id=shmget(0x124456,1024,IPC_CREAT|0664); if(shm_id<0){ perror("shmget:"); return 0; } //2.附加 void* addr=shmat(shm_id,NULL,0); if(NULL == addr){ perror("shmat:"); return 0; } printf("shmat addr:%p\n",addr); //3.写 return 0; }
- 2.3分离
- int shmdt (const void* shmaddr) ;
- 参数:
- shmaddr: shmat的返回值
- 返回值:
- 成功: 0
- 失败: -1
- 参数:
- 利用共享内存进行进程间通信
- 写:
-
#include <stdio.h> #include <unistd.h> #include <sys/shm.h> #include <string.h> int main(){ //1.获取共享内存 int shm_id=shmget(0x124456,1024,IPC_CREAT|0664); if(shm_id<0){ perror("shmget:"); return 0; } //2.附加 void* addr=shmat(shm_id,NULL,0); if(NULL == addr){ perror("shmat:"); return 0; } printf("shmat addr:%p\n",addr); //3.写 strcpy((char*)addr,"write prpcess..."); //shmdt(addr); return 0; }
- 读:
-
#include <stdio.h> #include <unistd.h> #include <sys/shm.h> int main(){ int shm_id=shmget(0x124456,1024,IPC_CREAT|0664); if(shm_id<0){ perror("shmget:"); return 0; } //附加 void* addr=shmat(shm_id,NULL,SHM_RDONLY); if(NULL == addr){ perror("shmat:"); return 0; } //读取 printf("read_shm:%s\n",(char*)addr); shmdt(addr); return 0; }
2 共享内存的特性
2.1生命周期跟随操作系统
- 可以通过ipcs命令查看消息队列,共享内存,信号量
2.2共享内存采用的是覆盖写的方式,读的时候, 是访问地址
- 覆盖写可以理解为,再次往共享内存中写的时候,会先将共享内存中的内容清空,再写入。
- 读的时候, 是访问地址,区别在管道当中学到的字节流,因为管道是将数据读走了,而在共享内存中读的时候并没有将数据读走,仅仅是访问地址。
2.3共享内存的删除特性
- 操作共享内存接口
- int shmct1(int shmid, int cmd, struct shmid_ds *buf)
- 参数:
- shmid:共享内存的操作句柄
- cmd : 告诉shmct1函数需要完成什么功能
- IPC_SET :设置共享内存属性信息(设置的时候为输入型参数)
- IPC_STAT :获取共享丙存属性信息(获取的时候为输出型参数)
- IPC_ RMID :删除共享内存,第三个参数传递NULL
- buf:共享内存数据结构buf
- 获取获取共享内存属性信息
-
#include <stdio.h> #include <unistd.h> #include <sys/shm.h> int main(){ int shm_id=shmget(0x12121212,1024,IPC_CREAT|0664); if(shm_id<0){ perror("shmget:"); return 0; } struct shmid_ds sd; shmctl(shm_id,IPC_STAT,&sd); printf("shm size : %ld\n",sd.shm_segsz); return 0; }
- 删除共享内存
-
#include <stdio.h> #include <unistd.h> #include <sys/shm.h> int main(){ int shm_id=shmget(0x12121212,1024,IPC_CREAT|0664); if(shm_id<0){ perror("shmget:"); return 0; } int count=20; while(count--){ sleep(1); printf("%d\n",count); } shmctl(shm_id,IPC_RMID,NULL); return 0; }
- ipcrm命令
- ipcrm -m [shmid]
- 一旦共享内存被删除掉之后, 共享内存在物理内存当中的空间被销毁了
- 如果删除共享内存的时候,共享内存附加的进程数最为0,则内核当中描述该共享内存的结构体也被释放了
- 如果删除的共享内存的时候,共享内存附加的进程数量不为0,则会将该共享内存的key,变成0x0000000。
- 表示当前共享内存不能被其他进程所附加,共享内存的状态会被设置为destory.
-
#include <stdio.h> #include <unistd.h> #include <sys/shm.h> #include <string.h> int main(){ //1.获取共享内存 int shm_id=shmget(0x124456,1024,IPC_CREAT|0664); if(shm_id<0){ perror("shmget:"); return 0; } //2.附加 void* addr=shmat(shm_id,NULL,0); if(NULL == addr){ perror("shmat:"); return 0; } printf("shmat addr:%p\n",addr); //3.写 strcpy((char*)addr,"write prpcess..."); //不让进程退出 while(1){ sleep(1); } shmdt(addr); return 0; }
-
附加的进程一旦全部退出之后,该共享内存在内核的结构体会被操作系统释放掉
-