一、概念
共享内存:允许在系统内两个或多个进程共享同一块内存空间,并且数据不用在客户进程和服务器进程间复制,因此共享内存
是通信速度最快的一种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 #include3 #include 4 #include 5 #include 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 #include3 #include 4 #include 5 #include 6 #include 7 #include 8 9 /******** 共享内存链接 ***********10 *1.获取shmid11 *2.连接共享内存12 *3.封装数据结构13 *4.写数据14 ***********************************/15 int main(int argc, char* argv[])16 {17 //1.获取shmid18 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 #include3 #include 4 #include 5 #include 6 #include 7 #include 8 9 /******** 共享内存链接 ***********10 *1.获取shmid11 *2.连接共享内存12 *3.封装数据结构13 *4.写数据14 ***********************************/15 16 int main(int argc, char* argv[])17 {18 //1.获取shmid19 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 #include3 #include 4 #include 5 #include 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下运行图: