POSIX 共享内存(Shared Memory)是一种进程间通信(IPC)机制,它允许多个进程共享同一块内存区域。POSIX 共享内存提供了创建、映射、取消映射和销毁共享内存段的功能。下面详细介绍 POSIX 共享内存的概念、用途、API 以及示例代码。
概述
POSIX 共享内存提供了一种方法,使得多个进程可以共享内存中的数据。与 System V 共享内存不同,POSIX 共享内存更简单易用,并且更加现代。
特点
- 跨进程:多个进程可以共享同一块内存区域。
- 持久性:共享内存段可以持久化存储在文件系统中。
- 匿名和命名:POSIX 共享内存支持匿名共享内存和命名共享内存。
- 内存映射文件:POSIX 共享内存可以基于文件或匿名内存区域。
API
POSIX 共享内存主要由以下几个函数组成:
创建共享内存
-
shm_open():
int shm_open(const char *name, int oflag, ... /* mode_t mode */)
: 创建或打开一个共享内存对象。- 参数
name
指定共享内存对象的名称,oflag
指定打开模式,如O_CREAT
表示创建新的共享内存对象,后面可以跟mode
来设置权限。
-
ftruncate():
int ftruncate(int fd, off_t length)
: 调整共享内存对象的大小。- 参数
fd
是共享内存对象的文件描述符,length
是新的大小。
映射共享内存
- mmap():
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
: 映射共享内存对象到进程地址空间。- 参数
addr
指定映射的起始地址,length
是映射的长度,prot
指定内存保护,flags
指定映射的选项,如MAP_SHARED
或MAP_PRIVATE
,fd
是共享内存对象的文件描述符,offset
是文件中的偏移量。
取消映射共享内存
- munmap():
int munmap(void *addr, size_t length)
: 取消映射共享内存。- 参数
addr
是映射的起始地址,length
是映射的长度。
删除共享内存
- shm_unlink():
int shm_unlink(const char *name)
: 删除共享内存对象。- 参数
name
是共享内存对象的名称。
示例代码
下面是一个简单的示例,展示了如何使用 POSIX 共享内存来在两个进程之间共享数据:
进程 A (processA.c)
1#include <fcntl.h>
2#include <sys/mman.h>
3#include <unistd.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#define SHM_NAME "/my_shm"
9#define SHM_SIZE 1024
10
11int main() {
12 int shm_fd;
13 char *shm_ptr;
14
15 // 创建共享内存对象
16 shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
17 if (shm_fd == -1) {
18 perror("shm_open");
19 exit(EXIT_FAILURE);
20 }
21
22 // 设置共享内存大小
23 if (ftruncate(shm_fd, SHM_SIZE) == -1) {
24 perror("ftruncate");
25 exit(EXIT_FAILURE);
26 }
27
28 // 映射共享内存到进程地址空间
29 shm_ptr = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
30 if (shm_ptr == MAP_FAILED) {
31 perror("mmap");
32 exit(EXIT_FAILURE);
33 }
34
35 // 写入数据
36 strncpy(shm_ptr, "Hello, World!", SHM_SIZE);
37
38 // 取消映射
39 if (munmap(shm_ptr, SHM_SIZE) == -1) {
40 perror("munmap");
41 exit(EXIT_FAILURE);
42 }
43
44 // 关闭文件描述符
45 if (close(shm_fd) == -1) {
46 perror("close");
47 exit(EXIT_FAILURE);
48 }
49
50 return 0;
51}
进程 B (processB.c)
1#include <fcntl.h>
2#include <sys/mman.h>
3#include <unistd.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#define SHM_NAME "/my_shm"
9#define SHM_SIZE 1024
10
11int main() {
12 int shm_fd;
13 char *shm_ptr;
14
15 // 打开共享内存对象
16 shm_fd = shm_open(SHM_NAME, O_RDWR, 0);
17 if (shm_fd == -1) {
18 perror("shm_open");
19 exit(EXIT_FAILURE);
20 }
21
22 // 映射共享内存到进程地址空间
23 shm_ptr = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
24 if (shm_ptr == MAP_FAILED) {
25 perror("mmap");
26 exit(EXIT_FAILURE);
27 }
28
29 // 读取数据
30 printf("Data in shared memory: %s\n", shm_ptr);
31
32 // 取消映射
33 if (munmap(shm_ptr, SHM_SIZE) == -1) {
34 perror("munmap");
35 exit(EXIT_FAILURE);
36 }
37
38 // 关闭文件描述符
39 if (close(shm_fd) == -1) {
40 perror("close");
41 exit(EXIT_FAILURE);
42 }
43
44 // 删除共享内存对象
45 if (shm_unlink(SHM_NAME) == -1) {
46 perror("shm_unlink");
47 exit(EXIT_FAILURE);
48 }
49
50 return 0;
51}
编译和运行
为了编译上述代码,你可以使用以下命令:
1gcc -o processA processA.c
2gcc -o processB processB.c
然后运行这两个进程:
1./processA &
2./processB
注意事项
- 在使用 POSIX 共享内存之前,确保检查所有 API 调用的返回值,以确保操作成功。
- 当使用完共享内存后,记得取消映射并删除共享内存对象以释放资源。
- 如果共享内存对象不再需要,应使用
shm_unlink()
删除它,以避免占用不必要的系统资源。 - 在实际应用中,可能需要处理更复杂的错误情况,比如处理映射失败的情况。
POSIX 共享内存提供了一种简单而强大的机制来进行进程间的共享数据,非常适合那些需要快速访问共享数据的应用场景。理解和熟练掌握这些 API 对于开发可靠的多进程应用程序非常重要。