什么是共享内存
共享内存是多个进程之间交换数据的一种高效方式。它允许不同程序访问同一块内存区域,避免了频繁的数据拷贝,特别适合对性能要求高的场景,比如音视频处理、实时通信等。
在实际开发中,比如做直播推流时,采集摄像头画面的进程和编码发送的进程就需要通过共享内存快速传递图像帧,这时候理解共享内存的使用流程就非常关键。
共享内存分配的基本步骤
使用共享内存通常包括创建或打开、映射到进程地址空间、读写操作以及释放四个阶段。
1. 创建或获取共享内存段
在 Linux 系统中,常用 shmget 函数来创建或访问一个共享内存段。需要指定一个 key 值作为标识,以及期望的内存大小和权限。
#include <sys/shm.h>
int shmid = shmget(0x1234, 4096, IPC_CREAT | 0666);
if (shmid == -1) {
perror("shmget failed");
return -1;
}这里的 key 是 0x1234,大小为 4096 字节,权限设为 0666,表示可读可写。
2. 将内存段映射到进程空间
创建之后,进程还不能直接访问这块内存,必须通过 shmat 把它挂载到自己的地址空间。
void *ptr = shmat(shmid, NULL, 0);
if (ptr == (void*)-1) {
perror("shmat failed");
return -1;
}执行后,ptr 就指向了共享内存的起始位置,后续可以通过指针读写数据。
3. 进行数据读写操作
现在多个进程只要用相同的 key 调用 shmget 和 shmat,就能拿到同一块内存的映射,实现数据共享。
比如一个进程写入字符串:
const char *msg = "Hello from process A";
memcpy(ptr, msg, strlen(msg) + 1);另一个进程就可以从中读出:
printf("Received: %s\n", (char*)ptr);4. 使用完成后解除映射并释放
当某个进程不再需要访问共享内存时,应调用 shmdt 解除映射。
if (shmdt(ptr) == -1) {
perror("shmdt failed");
}所有进程都使用完毕后,可以由其中一个进程删除共享内存段:
if (shmctl(shmid, IPC_RMID, NULL) == -1) {
perror("shmctl IPC_RMID failed");
}这样系统才会真正回收资源。
常见问题注意点
多个进程同时读写容易引发冲突,建议配合信号量或文件锁来协调访问顺序。例如两个进程同时往共享内存写数据,结果可能互相覆盖,导致数据错乱。
另外,忘记调用 shmctl 删除内存段会导致内存泄漏,即使程序退出,内核仍保留该段内存,需要用命令 ipcs -m 查看并手动清理。