十、进程间通信-共享内存
一、概述
-
共享内存用于用于进程间的数据共享,
-
开辟一块物理内存空间, 各个进程将同一块物理内存空间映射到自己的虚拟地址空间中, 通过虚拟地址进行访问, 进而实现数据共享
-
共享内存是最快的进程间通信方式, 因为通过虚拟地址空间映射后, 直接通过虚拟地址访问物理内存, 相较于其他方式少了两步数据拷贝的操作.
-
用于高效率传输大量数据
二、共享内存的用法
1、定义一个唯一key(ftok)
1 | key_t ftok( const char *pathname, int proj_id); |
2、构造一个共享内存对象(shmget)
(1)头文件
1 2 | #include <sys/ipc.h> #include <sys/shm.h> |
(2)函数原型
1 | int shmget(key_t key, int size, int shmflg) |
(3)参数
-
key: 键值;
-
size: 共享内存的大小。
-
shmflg:
-
IPC_CREATE:共享内存不存在则创建
-
mode:共享内存的权限
-
(4)返回值
-
成功:共享内存ID;
-
失败:-1
3、共享内存映射(shmat)
1 | int shmat( int shmid, const void *shmaddr, int shmflg) |
(1)参数
-
shmid:共享内存ID
-
shmaddr:映射地址,NULL为自动分配
-
shmflg:
-
SHM_RDONLY:只读方式映射
-
0:可读可写
-
(2)返回值
- 成功:共享内存首地址
- 失败:-1
4、解除共享内存映射(shmdt)
1 | int shmdt( const void *shmaddr) |
(1)参数
- shmaddr:映射的地址
(2)返回值
- 成功:0
- 失败:-1
5、删除共享内存(shmctl RMID)
1 | int shmctl( int shmid, int cmd, struct shmid_ds *buf) //获取或设置共享内存的相关属性 |
(1)参数:
-
shmid:共享内存ID
-
cmd:
-
- IPC_STAT:获取共享内存的属性信息
-
- IPC_SET:设置共享内存的属性
-
- IPC_RMID:删除共享内存
- buf:属性缓冲区
(2)返回值:
- 成功:由cmd类型决定
- 失败:-1
三、实例
使用共享内存,子进程拷贝数据到共享内存,父进程读取共享内存的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | #include<stdio.h> #include<string.h> #include<stdlib.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h> #include <sys/shm.h> #define DELAY_TIME 3 union semun{ int val; struct seimd_ds *buf; }; /*初始化信号量*/ int init_sem( int sem_id, int init_value) { union semun sem_union; sem_union.val = init_value; /*设置信号量集中的一个单独的信号量的值*/ if (semctl(sem_id,0,SETVAL,sem_union) == -1) { printf ( "Initialize semaphore failed!\n" ); return -1; } return 0; } /*删除信号量*/ int del_sem( int sem_id) { union semun sem_union; if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1) { perror ( "Delete semaohore fail!\n" ); return -1; } return 0; } /*P 操作:执行P操作时,信号量-1*/ int sem_p( int sem_id) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = -1; sops.sem_flg = SEM_UNDO; /*系统自动释放将会在系统中残留的信号量*/ if (semop(sem_id,&sops,1) == -1) { perror ( "P operation failed\n" ); return -1; } return 0; } /*V 操作:执行P操作时,信号量+1*/ int sem_v( int sem_id) { struct sembuf sops; sops.sem_num = 0; /*单个信号量的编号应该为 0*/ sops.sem_op = 1; /*表示V操作*/ sops.sem_flg = SEM_UNDO; /*系统自动释放将会在系统中残留的信号量*/ if (semop(sem_id,&sops,1) == -1) { perror ( "V operation failed\n" ); return -1; } return 0; } void main( void ) { pid_t result; int sem_id; int shm_id; char * addr; //这里6666的key也可以用ftok去生成 sem_id = semget((key_t)6666,1,0666|IPC_CREAT); /*创建一个信号量*/ shm_id = shmget((key_t)7777,1024,0666|IPC_CREAT); /*创建一个共享内存对象*/ init_sem(sem_id,0); //初始化信号量的值为0,只能先执行V操作+1,然后才能执行P操作-1 /*调用fork()函数*/ result = fork(); if (result == -1) { perror ( "Fork\n" ); } else if (result == 0) { printf ( "Child proess will wait for some seconds...\n" ); sleep(DELAY_TIME); /*映射共享内存*/ addr = shmat(shm_id,NULL,0); if (addr == ( void *)-1) { printf ( "shmat111 error!" ); exit (-1); } /*设置共享内存的内容*/ memcpy (addr, "helloworld" ,11); printf ( "the child process is running...\r\n" ); sem_v(sem_id); //如果有其他进程因等待信号量而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1. } else /*返回值大于0代表父进程*/ { sem_p(sem_id); //如果信号量等于0,则进程挂起,直到信号量大于0,执行V操作 printf ( "the father process is running...\r\n" ); /*映射共享内存地址*/ addr = shmat(shm_id,NULL,0); if (addr == ( void *)-1) { printf ( "shmat222 error!" ); exit (-1); } printf ( "shared memory string:%s\r\n" ,addr); /*解除共享内存映射*/ shmdt(addr); /*删除共享内存映射*/ shmctl(shm_id,IPC_RMID,NULL); /*删除信号量*/ del_sem(sem_id); } exit (0); } |
执行结果:
父进程读出了共享内存地址的数据helloworld,代码中的信号量用于共享资源的互斥。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库