Linux 系统中的 shmget() 函数详解
在 Linux 系统中,进程间通信(IPC, Inter-Process Communication)是实现多进程协同工作的重要机制,共享内存(Shared Memory)作为最高效的 IPC 方式之一,允许多个进程直接访问同一块物理内存区域,从而避免了数据在用户空间和内核空间之间的频繁拷贝,在 POSIX 和 System V 两种 IPC 接口中,System V 提供的 shmget() 函数是创建或获取共享内存段的核心系统调用,本文将详细介绍 shmget() 函数的原理、参数、返回值及使用场景,帮助读者深入理解共享内存机制。

函数原型与功能概述
shmget() 函数属于 System V IPC 接口,其原型定义在 <sys/shm.h> 头文件中,具体如下:
#include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg);
该函数的主要功能是根据给定的键值(key)创建或获取一个共享内存段,并返回该共享内存段的标识符(shmid),若共享内存段已存在,shmget() 会返回其标识符;若不存在且满足创建条件,则新建一个共享内存段。
参数详解
-
key(键值)
key是一个类型为key_t的值,用于唯一标识一个共享内存段,它通常由ftok()函数生成,该函数通过一个路径名和一个项目ID(通常为单字节整数)生成一个唯一的键值,若key设置为IPC_PRIVATE,则shmget()会强制创建一个新的共享内存段,即使该键值已存在。 -
size(内存段大小)
size指定要创建的共享内存段的大小(以字节为单位),若获取已存在的共享内存段,size可设为 0,但若新建内存段,size必须大于 0,实际分配的内存大小可能会向上取整到系统页面的整数倍(通常为 4KB)。
-
shmflg(标志位)
shmflg是一组标志位的按位或组合,用于控制共享内存段的创建权限和访问模式,常见的标志位包括:IPC_CREAT:若共享内存段不存在,则创建它;若已存在且未设置IPC_EXCL,则返回其标识符。IPC_EXCL:与IPC_CREAT联用,若共享内存段已存在,则返回错误。- 权限标志位:如
0666(读写权限),可通过 组合用户、组及其他用户的读、写、执行权限。
返回值与错误处理
- 成功时:返回非负整数的共享内存段标识符(
shmid),后续操作(如shmat()、shmdt()、shmctl())需通过该标识符引用该内存段。 - 失败时:返回
-1,并通过errno设置错误码,常见错误包括:EINVAL:参数size小于系统限制或key无效。EEXIST:设置了IPC_EXCL且共享内存段已存在。EACCES:无权限访问该共享内存段。ENOMEM:系统内存不足,无法分配请求的共享内存段。
共享内存段的创建与获取流程
- 生成唯一键值:通过
ftok()生成key,key_t key = ftok("/tmp", 'A'); - 创建或获取共享内存段:调用
shmget(),int shmid = shmget(key, 4096, IPC_CREAT | 0666);
- 错误检查:验证
shmid是否有效,若无效则打印错误信息并退出。
共享内存段的控制与管理
shmget() 创建的共享内存段需配合其他函数使用:
shmat():将共享内存段附加到进程的地址空间,返回指向内存段的指针。shmdt():分离已附加的共享内存段,仅解除映射,不释放内存。shmctl():控制共享内存段,包括获取状态(IPC_STAT)、删除(IPC_RMID)等操作。
删除共享内存段的代码如下:
shmctl(shmid, IPC_RMID, NULL);
使用场景与注意事项
- 高效数据传输:共享内存适用于需要频繁、大量数据交换的场景,如数据库缓存、实时数据处理等。
- 同步问题:共享内存本身不提供同步机制,需借助信号量(
semaphore)或互斥锁(mutex)避免数据竞争。 - 资源释放:使用完毕后需调用
shmctl()删除共享内存段,否则需手动清理(ipcrm -m shmid),否则可能导致内存泄漏。 - 权限控制:合理设置
shmflg的权限标志,避免未授权访问。
示例代码
以下是一个简单的父子进程通过共享内存通信的示例:

#include <stdio.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
key_t key = ftok("/tmp", 'A');
int shmid = shmget(key, 1024, IPC_CREAT | 0666);
char *str = (char *)shmat(shmid, NULL, 0);
if (fork() == 0) {
// 子进程写入数据
sprintf(str, "Hello from child process!");
shmdt(str);
exit(0);
} else {
// 父进程读取数据
wait(NULL);
printf("Parent received: %s\n", str);
shmdt(str);
shmctl(shmid, IPC_RMID, NULL);
}
return 0;
}
shmget() 作为 System V IPC 接口的核心函数,为 Linux 系统提供了高效的共享内存管理机制,通过合理设置参数和结合其他辅助函数,开发者可以轻松实现进程间的高效数据共享,使用时需注意同步问题、资源释放及权限控制,以确保系统的稳定性和安全性,掌握 shmget() 的原理与应用,对于深入理解 Linux 进程通信和系统编程具有重要意义。
















