当前位置: 首页 > news >正文

Linux 进程间通信:共享内存详解

文章目录

    • 1. 共享内存原理及使用场景
      • 原理
      • 使用场景
    • 2. 共享内存相关API接口
      • System V共享内存API
        • 1. `shmget` - 创建/获取共享内存段
        • 2. `shmat` - 附加共享内存段
        • 3. `shmdt` - 分离共享内存段
        • 4. `shmctl` - 控制共享内存段
      • POSIX共享内存API
        • 1. `shm_open` - 创建/打开共享内存对象
        • 2. `shm_unlink` - 删除共享内存对象
        • 3. `ftruncate` - 设置共享内存大小
        • 4. `mmap` - 内存映射
        • 5. `munmap` - 取消内存映射
    • 3. 实例代码
      • 示例1:System V共享内存
      • 示例2:POSIX共享内存
    • 4. 编译与运行
    • 注意事项

1. 共享内存原理及使用场景

原理

共享内存是最高效的进程间通信(IPC)方式之一,它允许多个进程访问同一块物理内存区域。其核心原理是:

  1. 在内存中创建一块共享区域
  2. 将这块内存映射到多个进程的地址空间
  3. 进程可以直接读写这块内存,无需内核干预

由于数据不需要在进程和内核之间复制,共享内存的通信速度非常快。

使用场景

共享内存适合以下场景:

  • 需要高性能的进程间通信
  • 需要传输大量数据
  • 进程间需要频繁交换数据
  • 对实时性要求高的应用

典型应用包括:

  • 数据库系统
  • 科学计算应用
  • 图形处理程序
  • 实时数据处理系统

2. 共享内存相关API接口

System V共享内存API

1. shmget - 创建/获取共享内存段
#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);
  • key: 共享内存键值,通常使用ftok生成或使用IPC_PRIVATE
  • size: 共享内存段大小(字节)
  • shmflg: 权限标志,常用组合:
    • IPC_CREAT | 0666:创建共享内存,权限为rw-rw-rw-
    • IPC_CREAT | IPC_EXCL | 0666:独占创建,若已存在则失败
  • 返回值:成功返回共享内存标识符,失败返回-1
2. shmat - 附加共享内存段
void *shmat(int shmid, const void *shmaddr, int shmflg);
  • shmid: shmget返回的标识符
  • shmaddr: 指定附加地址,通常为NULL让系统选择
  • shmflg:
    • SHM_RDONLY: 只读方式附加
    • 0: 读写方式附加
  • 返回值:成功返回附加后的地址指针,失败返回(void*)-1
3. shmdt - 分离共享内存段
int shmdt(const void *shmaddr);
  • shmaddr: shmat返回的地址指针
  • 返回值:成功返回0,失败返回-1
4. shmctl - 控制共享内存段
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  • shmid: 共享内存标识符
  • cmd: 控制命令
    • IPC_STAT: 获取状态信息
    • IPC_SET: 设置参数
    • IPC_RMID: 删除共享内存段
  • buf: 指向shmid_ds结构的指针
  • 返回值:成功返回0,失败返回-1

POSIX共享内存API

1. shm_open - 创建/打开共享内存对象
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>int shm_open(const char *name, int oflag, mode_t mode);
  • name: 共享内存对象名称,以/开头
  • oflag: 标志位,类似open:
    • O_CREAT: 不存在则创建
    • O_RDWR: 读写方式打开
    • O_EXCL: 与O_CREAT一起使用,确保独占创建
  • mode: 权限位
  • 返回值:成功返回文件描述符,失败返回-1
2. shm_unlink - 删除共享内存对象
int shm_unlink(const char *name);
  • name: 共享内存对象名称
  • 返回值:成功返回0,失败返回-1
3. ftruncate - 设置共享内存大小
int ftruncate(int fd, off_t length);
  • fd: 共享内存文件描述符
  • length: 要设置的大小
  • 返回值:成功返回0,失败返回-1
4. mmap - 内存映射
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
  • addr: 映射地址,通常为NULL让系统选择
  • length: 映射长度
  • prot: 保护模式
    • PROT_READ: 可读
    • PROT_WRITE: 可写
  • flags:
    • MAP_SHARED: 共享映射
    • MAP_PRIVATE: 私有映射
  • fd: 文件描述符
  • offset: 文件偏移量
  • 返回值:成功返回映射地址,失败返回MAP_FAILED
5. munmap - 取消内存映射
int munmap(void *addr, size_t length);
  • addr: 映射地址
  • length: 映射长度
  • 返回值:成功返回0,失败返回-1

3. 实例代码

示例1:System V共享内存

writer.c - 写入共享内存

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>#define SHM_SIZE 1024  // 共享内存大小int main() {key_t key = ftok("shmfile", 65);  // 生成key// 创建共享内存段int shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);if (shmid == -1) {perror("shmget failed");exit(EXIT_FAILURE);}// 附加到进程地址空间char *shm = (char*)shmat(shmid, NULL, 0);if (shm == (char*)-1) {perror("shmat failed");exit(EXIT_FAILURE);}printf("Write Data: ");fgets(shm, SHM_SIZE, stdin);  // 写入数据printf("Data written in memory: %s\n", shm);// 等待读取进程读取while (*shm != '*') {sleep(1);}// 分离共享内存shmdt(shm);// 删除共享内存shmctl(shmid, IPC_RMID, NULL);return 0;
}

reader.c - 从共享内存读取

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>#define SHM_SIZE 1024int main() {key_t key = ftok("shmfile", 65);  // 相同的key// 获取共享内存int shmid = shmget(key, SHM_SIZE, 0666);if (shmid == -1) {perror("shmget failed");exit(EXIT_FAILURE);}// 附加到进程地址空间char *shm = (char*)shmat(shmid, NULL, 0);if (shm == (char*)-1) {perror("shmat failed");exit(EXIT_FAILURE);}printf("Data read from memory: %s\n", shm);// 通知写入进程已完成读取*shm = '*';// 分离共享内存shmdt(shm);return 0;
}

示例2:POSIX共享内存

posix_writer.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>#define SHM_NAME "/my_shm"
#define SIZE 4096typedef struct {char data[SIZE];int ready;  // 1表示数据已准备好,0表示未准备好
} SharedData;int main() {int shm_fd;SharedData *shared_data;// 创建共享内存对象shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);if (shm_fd == -1) {perror("shm_open failed");exit(EXIT_FAILURE);}// 配置共享内存大小if (ftruncate(shm_fd, sizeof(SharedData)) == -1) {perror("ftruncate failed");close(shm_fd);shm_unlink(SHM_NAME);exit(EXIT_FAILURE);}// 内存映射shared_data = mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);if (shared_data == MAP_FAILED) {perror("mmap failed");close(shm_fd);shm_unlink(SHM_NAME);exit(EXIT_FAILURE);}// 初始化共享数据shared_data->ready = 0;printf("Writer: Enter data to write to shared memory: ");if (fgets(shared_data->data, SIZE, stdin) == NULL) {perror("fgets failed");munmap(shared_data, sizeof(SharedData));close(shm_fd);shm_unlink(SHM_NAME);exit(EXIT_FAILURE);}// 标记数据已准备好shared_data->ready = 1;printf("Writer: Data written to memory: %s", shared_data->data);// 等待读者读取完成printf("Writer: Waiting for reader to finish...\n");while (shared_data->ready == 1) {sleep(1);}printf("Writer: Reader has finished reading.\n");// 清理if (munmap(shared_data, sizeof(SharedData)) == -1) {perror("munmap failed");}if (close(shm_fd) == -1) {perror("close failed");}if (shm_unlink(SHM_NAME) == -1) {perror("shm_unlink failed");}return 0;
}

posix_reader.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>#define SHM_NAME "/my_shm"
#define SIZE 4096typedef struct {char data[SIZE];int ready;  // 1表示数据已准备好,0表示未准备好
} SharedData;int main() {int shm_fd;SharedData *shared_data;// 打开共享内存对象shm_fd = shm_open(SHM_NAME, O_RDWR, 0666);if (shm_fd == -1) {perror("shm_open failed");exit(EXIT_FAILURE);}// 内存映射shared_data = mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);if (shared_data == MAP_FAILED) {perror("mmap failed");close(shm_fd);exit(EXIT_FAILURE);}// 等待数据准备好printf("Reader: Waiting for data to be ready...\n");while (shared_data->ready == 0) {sleep(1);}// 读取数据printf("Reader: Data read from memory: %s", shared_data->data);// 通知写入者已完成读取shared_data->ready = 0;// 清理if (munmap(shared_data, sizeof(SharedData)) == -1) {perror("munmap failed");}if (close(shm_fd) == -1) {perror("close failed");}return 0;
}

4. 编译与运行

在这里插入图片描述

# 编译
gcc posix_writer.c -o posix_writer -lrt
gcc posix_reader.c -o posix_reader -lrt# 运行(需要先运行writer)
./posix_writer
# 在另一个终端
./posix_reader

注意事项

  1. 共享内存没有内置的同步机制,通常需要配合信号量或互斥锁使用

  2. 使用完毕后应及时释放资源,避免内存泄漏

  3. 在多进程访问时要注意数据一致性问题

  4. System V共享内存是持久的,即使没有进程附加也会保留,需要显式删除

  5. POSIX共享内存通常挂载在/dev/shm目录下
    在这里插入图片描述

http://www.dtcms.com/a/296897.html

相关文章:

  • 2025年人形机器人动捕技术研讨会于7月31日在京召开
  • 如何使用 pdfMake 中文字体
  • Next.js 中配置不同页面布局方案
  • 无锡市亨达电机盛装亮相 2025上海生物发酵展引关注
  • 深入理解大语言模型生成参数:temperature、top\_k、top\_p 等全解析
  • 首发即开源!DAWorkBench数据可视化分析软件正式发布!(附源码下载网址)
  • ubuntu安装teams解决方法
  • JavaScript中this的5大核心规则详解
  • vue 项目中 components 和 views 包下的组件功能区别对比,示例演示
  • Eureka-服务注册,服务发现
  • CSDN技术专栏开篇:高效开发环境搭建指南
  • Android Activity与Fragment生命周期变化
  • 深度学习(鱼书)day01--感知机
  • springboot实战篇2
  • 磁悬浮转子不平衡质量控制:比例谐振控制器深度解析
  • iOS网络之异步加载
  • Win10系统自带输入法打字,莫名切全角英文字母变大问题
  • Linux驱动18 --- LCD 屏
  • Ubuntu同一网段下配置多个雷达
  • 大模型开发框架LangChain之集成MCP工具
  • MC0461排队
  • 【时时三省】(C语言基础)怎样定义和使用指向函数的指针变量
  • 深入解析Java微服务架构请求流程:Nginx到Nacos的完整旅程
  • 数据库期中复习
  • JSONObject相关知识点
  • 嵌入式通信知识串讲:从同步 / 异步传输到 UART 协议 STM32F103 硬件解析
  • 大模型提示词漏洞攻防测试:技术分析与实践指南
  • 客户关系管理(CRM)百科:定义、价值及发展趋势
  • JMeter 性能测试实战笔记
  • Javascript NaN Symbol BigInt