2.共享内存
一、概念
共享内存:允许在系统内两个或多个进程共享同一块内存空间,并且数据不用在客户进程和服务器进程间复制,因此共享内存
是通信速度最快的一种IPC。
实现机制:一个进程在系统中申请开辟一块共享内存空间,然后使用这个共享内存空间的各个进程分别打开这个共享内存空间,
并将这个内存空间映射到自己的进程空间上,这样各个进程就可以共同使用这个共享内存空间,就如同使用自己进程
地址空间的内存一样,达到对内存的读写操作。
共享内存相关函数:
头文件: #include <sys/ipc.h> #include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg); //1.创建或获取共享内存
void *shmat(int shmid,const void* shmaddr,int shmflg); //2.进程链接共享内存
int shmdt(const void* shmaddr); //3.共享内存与当前进程脱离开
int shmctl(int shmid, int cmd, struct shmid_ds *buf); //4.共享内存控制函数
二、函数参数介绍
1.shmget函数 :创建或获取共享内存
int shmget(key_t key,size_t size, int shmflg); key: 创建或获取共享内存段的键值
size: 共享的内存空间
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样
如果共享内存创建成功,shmget将返回一个非负整数,即该段共享内存的标识码;如果失败,则返回“-1”
2.shmmat函数 :内存段刚创建,任何进程都不能访问该内存段。只有当内存空间映射到进程空间中,该进程
才能访问共享内存。(建立地址映射,进程连接)
void* shmat(int shm_id, const void *shm_addr, int shmflg);
shm_id: shmget返回的共享内存标识码
shm_addr:把共享内存连接到当前进程去的时候准备放置它的那个地址
注: 1.shmaddr为0,核心自动选择一个地址(一般自动设置)
2.shmaddr不为0且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmflg是一组按位OR(或)在一起的标志。它的两个可能取值是SHM_RND和SHM_RDONLY
调用成功,返回指针,指针指向共享内存的第一个字节;失败,则返回“-1”
其中:
1.在fork() 后,子进程继承已连接的共享内存
2.在exec后,已连接的共享内存会自动脱离(detach)
3.在结束进程后,已连接的共享内存会自动脱离(detach)
3.shmdt函数 :共享内存与当前进程脱离开
int shmdt(const void *shm_addr);
shm_addr: 由shmat返回的地址指针
操作成功,返回“0”,失败则返回“-1”
注:脱离共享内存并不等于删除它,只是当前进程不能再继续访问它而已。
4.shmctl函数 :共享内存控制函数
int shmctl(int shm_id,int command, struct shmid_ds *buf);
shm_id: 由shmget返回的共享内存标识码 command:将要采取的动作(有三个可取值)
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
操作成功,返回0,失败则返回-1
三、代码实例
创建共享内存,并不同进程对创建的共享内存读写操作,最后删除该共享内存。
1.创建共享内存: shmget.c文件
1 #include "stu.h" 2 #include<stdio.h> 3 #include<sys/ipc.h> 4 #include<sys/shm.h> 5 #include<stdlib.h> 6 7 int main() 8 { 9 int shmid = shmget((key_t)0x1001, sizeof(stu_t)*10, IPC_CREAT | IPC_EXCL | 0666); 10 if(shmid == -1) 11 { 12 perror("shmget"); 13 exit(EXIT_FAILURE); 14 } 15 printf("shared memory created success, shmid = %d", shmid); 16 return 0; 17 }
2.往共享内存写数据 shmput.c文件
1 #include "stu.h" 2 #include<stdio.h> 3 #include<sys/ipc.h> 4 #include<sys/shm.h> 5 #include<stdlib.h> 6 #include<unistd.h> 7 #include<string.h> 8 9 /******** 共享内存链接 *********** 10 *1.获取shmid 11 *2.连接共享内存 12 *3.封装数据结构 13 *4.写数据 14 ***********************************/ 15 int main(int argc, char* argv[]) 16 { 17 //1.获取shmid 18 int shmid = shmget((key_t)0x1001, 10, 0); 19 if(shmid == -1) 20 { 21 perror("shmget"); 22 exit(EXIT_FAILURE); 23 } 24 //2.连接共享内存 25 void *pShm = shmat(shmid, 0, 0); 26 if(pShm == (void*)-1) 27 { 28 perror("shmat"); 29 exit(EXIT_FAILURE); 30 } 31 //3.封装数据结构 32 stu_t aStu = {1001, "Tom"}; 33 //4.写数据 34 memcpy(pShm, &aStu, sizeof(stu_t)); 35 //5.用完了就要断开连接 36 if(shmdt(pShm)!= 0) 37 { 38 perror("shmdt"); 39 exit(EXIT_FAILURE); 40 } 41 return 0; 42 }
3.从共享内存读数据 shmread.c文件
1 #include "stu.h" 2 #include<stdio.h> 3 #include<sys/ipc.h> 4 #include<sys/shm.h> 5 #include<stdlib.h> 6 #include<unistd.h> 7 #include<string.h> 8 9 /******** 共享内存链接 *********** 10 *1.获取shmid 11 *2.连接共享内存 12 *3.封装数据结构 13 *4.写数据 14 ***********************************/ 15 16 int main(int argc, char* argv[]) 17 { 18 //1.获取shmid 19 int shmid = shmget((key_t)0x1001, 10, 0); 20 if(shmid == -1) 21 { 22 perror("shmget"); 23 exit(EXIT_FAILURE); 24 } 25 //2.连接共享内存 26 void *pShm = shmat(shmid, 0, 0); 27 if(pShm == (void*)-1) 28 { 29 perror("shmat"); 30 exit(EXIT_FAILURE); 31 } 32 //3.封装数据结构 33 stu_t aStu = {0}; 34 //4.写数据 35 memcpy(&aStu, pShm, sizeof(stu_t)); 36 printf("get shmid = %d, name = %s\n", aStu.id, aStu.name); 37 //5.用完了就要断开连接 38 if(shmdt(pShm)!= 0) 39 { 40 perror("shmdt"); 41 exit(EXIT_FAILURE); 42 } 43 return 0; 44 }
4.删除共享内存 shmctl.c文件
1 #include "stu.h" 2 #include<stdio.h> 3 #include<sys/ipc.h> 4 #include<sys/shm.h> 5 #include<stdlib.h> 6 7 int main() 8 { 9 int shmid = shmget((key_t)0x1001, 10 , 0); 10 if(shmid == -1) 11 { 12 perror("shmget"); 13 exit(EXIT_FAILURE); 14 } 15 if(shmctl(shmid, IPC_RMID, NULL) == -1) 16 { 17 perror("shmctl"); 18 exit(EXIT_FAILURE); 19 } 20 return 0; 21 }
5.公有文件: stu.h
1 #ifndef _STU_H 2 #define _STU_H 3 4 typedef struct student_s 5 { 6 int id; 7 char name[32]; 8 }stu_t; 9 10 #endif
Linux下运行图: