Linux IPC:POSIX共享内存汇总整理

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_SHAREDMAP_PRIVATEfd是共享内存对象的文件描述符,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 对于开发可靠的多进程应用程序非常重要。