共享内存
共享内存是我们进程间通信最快的一种方式,那么为什么可以这样说呢?
那么咱们先来看看共享内存的通信原理。
上图是我画的利用共享内存通信的示意图。其实看了图我想你应该就明白共享内存通信是怎么一回事了
- 基本思想:多个进程通过将同一块物理内存映射到自己的虚拟地址空间中,实现了多个进程可以对同一块物理内存进行操作,通过这种方式我们就实现了数据共享的功能。
为什么利用共享内存通信最快
- 那么为什么会说共享内存是进程间通信最快的一种方式呢,看到上面的示意图,以及我们以前讨论过的进程间通信的其它方式,我想你就明白了,对于其它方式而言,例如管道,它是将数据拷贝到内核中的缓冲区,再从缓冲区中将数据拷贝出来,而我们的共享内存是直接通信将同一块物理内存映射到自己的虚拟地址空间中,那么多个进程同用同一块物理内存,这样就少了数据的拷贝工作,所以效率会更高。
具体的利用共享内存通信的步骤
-
1、创建共享内存
接口:int shmget(key_t key,size_t size , int shmflg)
key: 共享内存标识符
size: 共享内存大小
shmflg: 选项标志
(IPC_CREAT)共享内存不存在则创建,存在则打开
(IPC_EXCL) 不存在则创建,存在则报错
(shm_mode) 权限
返回值:标识符 失败:-1 -
2、 建立映射
接口 : void* shmat(int shmid, const void* shmaddr,int shmflg)
shmid:创建共享内存返回的句柄
shmaddr:共享内存首地址,一般置空,由操作系统自行分配
shmflg:映射成功后的操作权限
(SHM_RDONLY)只读
(0) 默认可读可写 -
3、解除映射
接口:int shmdt(const void* shmaddr)
shmflg:共享内存的首地址 -
4、删除共享内存
接口: int shmct(int shmid , int cmd , struct shmid_ds * buf)
shmid:操作句柄
cmd:操作类型(一般选IPC_RMID删除共享内存)
buf: 设置/获取共享内存信息
注:共享内存不会被直接删除,而是判断映射连接数是否为0,如果为0,则直接删除,否则,拒绝后序其它进程映射连接,当映射连接数为0时,自动删除。
- 简单代码示例
读数据
1 *************************************************************************
2 *> File Name: shm.c
3 *> Author: san
4 *> Created Time: 2019年04月17日 星期三 19时26分17秒
5 *> Describe: 共享内存的基本操作
6 1. 创建
7 2. 建立映射
8 3. 内存操作
9 4. 解除映射
10 5. 删除
11 *************************************************************************/
12
13 #include <stdio.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <sys/shm.h>
18 #define IPC_KEY 0x12345678
19 #define PROJ_ID 0X112233
20 int main(int argc, char *argv[])
21 {
22 //1. 创建
23 //key_t ftok(const char *pathname, int proj_id);
24 // 通过文件inode节点号与proj_id生成一个key值
25 //int shmget(key_t key, size_t size, int shmflg);
26 // key: 共享内存标识符
27 // size: 共享内存大小
28 // shmflg:选项标志
29 // IPC_CREAT 共享内存不存在则创建,存在则打开
30 // IPC_EXCL 与IPC_CREAT同用,则共享内存存在时报错
31 // shm_mode 权限
32 // 返回值:标识符(代码中的操作句柄) 失败:-1
33 //key_t key = ftok(".", PROJ_ID);
34 int shmid = shmget(IPC_KEY, 32, IPC_CREAT | 0664);
35 if (shmid < 0) {
36 perror("shmget error");
37 return -1;
38 }
39 //建立映射
40 //void *shmat(int shmid, const void *shmaddr, int shmflg);
41 // shmid: 创建共享内存,返回的句柄
42 // shmaddr:置空-映射首地址由操作系统分配
43 // shmflg: 映射成功后的操作权限
44 // SHM_RDONLY 只读
45 // 0 默认-可读可写
46 // 返回值:映射首地址 失败:(void*)-1
47 char *shm_start = shmat(shmid, NULL, 0);
48 if (shm_start == (void*)-1) {
49 perror("shmat error");
50 return -1;
51 }
52 int i = 0;
53 while(1) {
54 printf("%s", shm_start);
55 sleep(1);
56 }
57 //解除映射
58 //int shmdt(const void *shmaddr);
59 // shmaddr: 映射首地址
60 shmdt(shm_start);
61 //删除
62 //int shmctl(int shmid, int cmd, struct shmid_ds *buf);
63 // shmid: 操作句柄
64 // cmd: 操作类型
65 // IPC_RMID 删除共享内存
66 // buf: 设置/获取共享内存信息
67 //
68 shmctl(shmid, IPC_RMID, NULL);
69 return 0;
70 }
写数据
1 /*************************************************************************
2 *> File Name: shm.c
3 *> Author: san
4 *> Created Time: 2019年04月17日 星期三 19时26分17秒
5 *> Describe: 共享内存的基本操作
6 1. 创建
7 2. 建立映射
8 3. 内存操作
9 4. 解除映射
10 5. 删除
11 *************************************************************************/
12
13 #include <stdio.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <sys/shm.h>
18 #define IPC_KEY 0x12345678
19 #define PROJ_ID 0X112233
20 int main(int argc, char *argv[])
21 {
22 //1. 创建
23 //key_t ftok(const char *pathname, int proj_id);
24 // 通过文件inode节点号与proj_id生成一个key值
25 //int shmget(key_t key, size_t size, int shmflg);
26 // key: 共享内存标识符
27 // size: 共享内存大小
28 // shmflg:选项标志
29 // IPC_CREAT 共享内存不存在则创建,存在则打开
30 // IPC_EXCL 与IPC_CREAT同用,则共享内存存在时报错
31 // shm_mode 权限
32 // 返回值:标识符(代码中的操作句柄) 失败:-1
33 //key_t key = ftok(".", PROJ_ID);
34 int shmid = shmget(IPC_KEY, 32, IPC_CREAT | 0664);
35 if (shmid < 0) {
36 perror("shmget error");
37 return -1;
38 }
39 //建立映射
40 //void *shmat(int shmid, const void *shmaddr, int shmflg);
41 // shmid: 创建共享内存,返回的句柄
42 // shmaddr:置空-映射首地址由操作系统分配
43 // shmflg: 映射成功后的操作权限
44 // SHM_RDONLY 只读
45 // 0 默认-可读可写
46 // 返回值:映射首地址 失败:(void*)-1
47 char *shm_start = shmat(shmid, NULL, 0);
48 if (shm_start == (void*)-1) {
49 perror("shmat error");
50 return -1;
51 }
52 int i = 0;
53 while(1) {
54 sprintf(shm_start, "你瞅啥,瞅你咋的~~ +%d\n", i++);
55 sleep(1);
56 }
57 //解除映射
58 //int shmdt(const void *shmaddr);
59 // shmaddr: 映射首地址
60 shmdt(shm_start);
61 //删除
62 //int shmctl(int shmid, int cmd, struct shmid_ds *buf);
63 // shmid: 操作句柄
64 // cmd: 操作类型
65 // IPC_RMID 删除共享内存
66 // buf: 设置/获取共享内存信息
67 //共享内存不会被直接删除,而是判断映射连接数是否为0
68 // 为0: 直接删除
69 // 不为0: 拒绝后续其它进程的映射连接,当映射连接数为0时自动删除
70 shmctl(shmid, IPC_RMID, NULL);
71 return 0;
72 }
以上就是我们关于进程间通信共享内存的简介,你现在了解了吗?