Linux IPC:System V共享内存汇总整理
System V 共享内存是 Unix 和类 Unix 操作系统中的一种进程间通信(IPC)机制,它允许进程之间共享同一块内存区域。System V 共享内存是 System V IPC 标准的一部分,该标准还包括信号量和消息队列等其他 IPC 机制。
概述
System V 共享内存允许进程通过映射同一块内存区域来共享数据。与其他 IPC 机制相比,共享内存提供了更高的效率,因为它不需要复制数据就可以在进程之间传递信息。
特点
- 持久性:共享内存段可以持久存储在内核中,即使创建它的进程终止后仍然存在。
- 跨进程:共享内存可以在没有亲缘关系的进程之间进行通信。
- 属性配置:可以配置共享内存段的属性,如最大大小等。
API
System V 共享内存主要由以下几个函数组成:
创建共享内存段
- shmget():
int shmget(key_t key, size_t size, int shmflg)
: 创建或打开共享内存段。- 参数
key
是标识共享内存段的键值,size
指定共享内存段的大小,shmflg
指定标志位,可以包含IPC_CREAT
来创建新的共享内存段,也可以包含IPC_EXCL
来防止创建已存在的共享内存段。
映射共享内存
- shmat():
void *shmat(int shmid, const void *shmaddr, int shmflg)
: 将共享内存段映射到进程地址空间。- 参数
shmid
是共享内存段标识符,shmaddr
指定映射的起始地址,如果为NULL
则由系统选择,shmflg
指定标志位。
取消映射共享内存
- shmdt():
int shmdt(const void *shmaddr)
: 取消映射共享内存段。- 参数
shmaddr
是映射的起始地址。
删除共享内存段
- shmctl():
int shmctl(int shmid, int cmd, ... /* union shmid_ds *buf */)
: 控制共享内存段。- 参数
shmid
是共享内存段标识符,cmd
指定命令,如IPC_RMID
用于删除共享内存段,后面的参数根据命令的不同而变化。
示例代码
下面是一个简单的示例,展示了如何使用 System V 共享内存来在两个进程之间共享数据:
进程 A (processA.c)
1#include <sys/types.h>
2#include <sys/ipc.h>
3#include <sys/shm.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#define SHM_KEY 12345
9#define SHM_SIZE 1024
10
11int main() {
12 int shmid;
13 char *shm_ptr;
14
15 // 创建共享内存段
16 shmid = shmget(SHM_KEY, SHM_SIZE, 0666 | IPC_CREAT);
17 if (shmid == -1) {
18 perror("shmget");
19 exit(EXIT_FAILURE);
20 }
21
22 // 映射共享内存段到进程地址空间
23 shm_ptr = shmat(shmid, NULL, 0);
24 if (shm_ptr == (void *)-1) {
25 perror("shmat");
26 exit(EXIT_FAILURE);
27 }
28
29 // 写入数据
30 strncpy(shm_ptr, "Hello, World!", SHM_SIZE);
31
32 // 取消映射
33 if (shmdt(shm_ptr) == -1) {
34 perror("shmdt");
35 exit(EXIT_FAILURE);
36 }
37
38 return 0;
39}
进程 B (processB.c)
1#include <sys/types.h>
2#include <sys/ipc.h>
3#include <sys/shm.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#define SHM_KEY 12345
9#define SHM_SIZE 1024
10
11int main() {
12 int shmid;
13 char *shm_ptr;
14
15 // 打开共享内存段
16 shmid = shmget(SHM_KEY, SHM_SIZE, 0666);
17 if (shmid == -1) {
18 perror("shmget");
19 exit(EXIT_FAILURE);
20 }
21
22 // 映射共享内存段到进程地址空间
23 shm_ptr = shmat(shmid, NULL, 0);
24 if (shm_ptr == (void *)-1) {
25 perror("shmat");
26 exit(EXIT_FAILURE);
27 }
28
29 // 读取数据
30 printf("Data in shared memory: %s\n", shm_ptr);
31
32 // 取消映射
33 if (shmdt(shm_ptr) == -1) {
34 perror("shmdt");
35 exit(EXIT_FAILURE);
36 }
37
38 // 删除共享内存段
39 if (shmctl(shmid, IPC_RMID, NULL) == -1) {
40 perror("shmctl");
41 exit(EXIT_FAILURE);
42 }
43
44 return 0;
45}
编译和运行
为了编译上述代码,你可以使用以下命令:
1gcc -o processA processA.c
2gcc -o processB processB.c
然后运行这两个进程:
1./processA &
2./processB
注意事项
- 在使用 System V 共享内存之前,确保检查所有 API 调用的返回值,以确保操作成功。
- 当使用完共享内存后,记得取消映射并删除共享内存段以释放资源。
- 如果共享内存段不再需要,应使用
shmctl()
的IPC_RMID
命令删除它,以避免占用不必要的系统资源。 - 在实际应用中,可能需要处理更复杂的错误情况,比如处理映射失败的情况。
System V 共享内存提供了一种简单而强大的机制来进行进程间的共享数据,非常适合那些需要快速访问共享数据的应用场景。理解和熟练掌握这些 API 对于开发可靠的多进程应用程序非常重要。