进程间通信(IPC)的共享内存机制允许不同进程直接访问同一块物理内存区域,是速度最快的IPC方式(无需数据拷贝)。
一、共享内存核心概念
1. 基本原理
- 共享内存区域:由内核管理的特殊内存段,可被多个进程映射到自身地址空间。
- 零拷贝:进程直接读写内存,无需通过内核缓冲区(如管道/消息队列需要)。
- 需同步:必须配合信号量/互斥锁等机制,避免数据竞争。
2. 生命周期
- 创建:
shmget
(System V)或shm_open
(POSIX) - 映射:
shmat
或mmap
- 销毁:
shmctl
或shm_unlink
二、System V 共享内存基础示例
1. 创建共享内存
#include <sys/ipc.h>
#include <sys/shm.h>int main() {key_t key = ftok("shmfile", 65); // 生成唯一keyint shmid = shmget(key, 1024, 0666|IPC_CREAT); // 创建1024字节共享内存char *str = (char*) shmat(shmid, (void*)0, 0); // 映射到进程地址空间sprintf(str, "Hello Shared Memory!"); // 写入数据shmdt(str); // 解除映射return 0;
}
2. 另一个进程读取数据
int main() {key_t key = ftok("shmfile", 65);int shmid = shmget(key, 1024, 0666);char *str = (char*) shmat(shmid, (void*)0, 0);printf("Data read: %s\n", str);shmdt(str);shmctl(shmid, IPC_RMID, NULL); // 销毁共享内存return 0;
}
三、POSIX 共享内存进阶示例
1. 使用 mmap
和 shm_open
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>int main() {const char* name = "/my_shm";int fd = shm_open(name, O_CREAT | O_RDWR, 0666); // 创建POSIX共享内存对象ftruncate(fd, 1024); // 设置大小char *ptr = mmap(0, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);sprintf(ptr, "Hello POSIX SHM!");munmap(ptr, 1024);close(fd);shm_unlink(name); // 删除共享对象return 0;
}
2. 配合信号量同步
#include <semaphore.h>// 写入进程
sem_t *sem = sem_open("/my_sem", O_CREAT, 0666, 1); // 初始化信号量为1
sem_wait(sem); // P操作
sprintf(ptr, "New Data with Sync");
sem_post(sem); // V操作// 读取进程
sem_t *sem = sem_open("/my_sem", 0);
sem_wait(sem);
printf("Data: %s", ptr);
sem_post(sem);
四、深入理解共享内存
1. 性能优势场景
- 大数据传输:如视频处理、科学计算
- 实时性要求高:高频交易系统
2. 风险与缺陷
- 数据竞争:必须强制同步
- 内存泄漏:需显式销毁共享段
- 安全风险:所有进程均可访问
3. 高级技术扩展
- 匿名共享内存:
mmap
使用MAP_ANONYMOUS
,适用于父子进程 - 共享内存数据库:Redis的持久化内存设计
- 跨网络共享内存:如RDMA(远程直接内存访问)
五、关键系统调用对比
函数 | 用途 | System V | POSIX |
---|---|---|---|
shmget | 创建/获取共享内存 | ✔️ | ❌ |
shmat | 映射共享内存 | ✔️ | ❌ |
shmdt | 解除映射 | ✔️ | ❌ |
mmap | 内存映射文件/共享内存 | ❌ | ✔️ |
shm_open | 创建POSIX共享内存对象 | ❌ | ✔️ |
通过上述示例和解析,可以掌握共享内存的核心原理与实践技巧。实际开发中需结合场景选择System V或POSIX标准,并始终关注同步问题。