如何设置linux的共享内存
- Linux
- 2025-07-11
- 4616
shmget创建共享内存段,用
shmat附加到进程地址空间,访问修改后以
shmdt分离,最后用
shmctl删除
Linux系统中,共享内存是一种高效的进程间通信(IPC)机制,允许多个进程直接访问同一块内存区域,从而实现快速的数据交换,以下是设置Linux共享内存的详细步骤和相关说明:
创建共享内存段
在Linux中,可以使用shmget系统调用来创建或获取一个共享内存段,这个函数通常用于System V IPC(进程间通信)机制,以下是一个基本的示例代码:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
int main() {
key_t key = ftok("somefile", 'R'); // 生成唯一的键值
int shmid = shmget(key, 1024, 0666|IPC_CREAT); // 创建共享内存段
if (shmid == -1) {
perror("shmget failed");
return 1;
}
printf("Shared memory created with id: %d
", shmid);
return 0;
}
在这个示例中,ftok函数用于生成一个唯一的键值,shmget函数用于创建共享内存段。1024是共享内存段的大小,0666是权限标志,IPC_CREAT表示如果共享内存段不存在则创建它。
附加到共享内存段
创建共享内存段后,进程需要将其附加到自己的地址空间中,以便进行读写操作,可以使用shmat系统调用来实现这一点,以下是一个示例代码:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
int main() {
key_t key = ftok("somefile", 'R');
int shmid = shmget(key, 1024, 0666|IPC_CREAT);
if (shmid == -1) {
perror("shmget failed");
return 1;
}
char data = (char ) shmat(shmid, NULL, 0); // 附加到共享内存段
if (data == (char ) -1) {
perror("shmat failed");
return 1;
}
printf("Shared memory attached at address: %p
", data);
return 0;
}
在这个示例中,shmat函数将共享内存段附加到当前进程的地址空间中,并返回指向该内存段的指针。
读写共享内存
附加到共享内存段后,进程可以像操作普通内存一样读写共享内存,以下是一个示例代码:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
int main() {
key_t key = ftok("somefile", 'R');
int shmid = shmget(key, 1024, 0666|IPC_CREAT);
if (shmid == -1) {
perror("shmget failed");
return 1;
}
char data = (char ) shmat(shmid, NULL, 0);
if (data == (char ) -1) {
perror("shmat failed");
return 1;
}
strcpy(data, "Hello, World!"); // 写入数据到共享内存
printf("Data written to shared memory: %s
", data);
return 0;
}
在这个示例中,strcpy函数将字符串”Hello, World!”写入共享内存,其他进程也可以附加到同一个共享内存段,并读取或修改其中的数据。

分离和删除共享内存段
当进程不再需要访问共享内存时,可以使用shmdt系统调用将其从当前进程的地址空间中分离,共享内存段不再使用时,可以使用shmctl系统调用将其删除,以下是一个示例代码:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
int main() {
key_t key = ftok("somefile", 'R');
int shmid = shmget(key, 1024, 0666|IPC_CREAT);
if (shmid == -1) {
perror("shmget failed");
return 1;
}
char data = (char ) shmat(shmid, NULL, 0);
if (data == (char ) -1) {
perror("shmat failed");
return 1;
}
strcpy(data, "Hello, World!");
printf("Data written to shared memory: %s
", data);
if (shmdt(data) == -1) { // 分离共享内存段
perror("shmdt failed");
return 1;
}
printf("Shared memory detached
");
if (shmctl(shmid, IPC_RMID, NULL) == -1) { // 删除共享内存段
perror("shmctl failed");
return 1;
}
printf("Shared memory removed
");
return 0;
}
在这个示例中,shmdt函数将共享内存段从当前进程的地址空间中分离,shmctl函数将共享内存段从系统中删除。
使用POSIX共享内存
除了System V共享内存外,Linux还支持POSIX共享内存,POSIX共享内存的使用方式与System V有所不同,但同样可以实现进程间通信,以下是一个简单的POSIX共享内存示例:

#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main() {
int fd = shm_open("/myshm", O_CREAT|O_RDWR, 0666); // 创建共享内存对象
if (fd == -1) {
perror("shm_open failed");
return 1;
}
if (ftruncate(fd, 1024) == -1) { // 设置共享内存大小
perror("ftruncate failed");
return 1;
}
char data = (char ) mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); // 映射共享内存
if (data == MAP_FAILED) {
perror("mmap failed");
return 1;
}
strcpy(data, "Hello, POSIX!"); // 写入数据到共享内存
printf("Data written to shared memory: %s
", data);
if (munmap(data, 1024) == -1) { // 取消映射
perror("munmap failed");
return 1;
}
if (shm_unlink("/myshm") == -1) { // 删除共享内存对象
perror("shm_unlink failed");
return 1;
}
return 0;
}
在这个示例中,shm_open函数用于创建共享内存对象,ftruncate函数用于设置共享内存的大小,mmap函数用于将共享内存映射到进程的地址空间中。munmap函数用于取消映射,shm_unlink函数用于删除共享内存对象。
归纳对比表
| 特性 | System V共享内存 | POSIX共享内存 |
|---|---|---|
| 创建方式 | shmget |
shm_open |
| 附加方式 | shmat |
mmap |
| 分离方式 | shmdt |
munmap |
| 删除方式 | shmctl with IPC_RMID |
shm_unlink |
| 键值生成 | ftok |
路径名作为键值 |
| 权限控制 | shmflg参数 |
shm_open的第三个参数 |
| 适用场景 | 传统IPC需求 | 现代POSIX标准需求 |
| 可移植性 | 特定于System V | 更符合POSIX标准,跨平台更好 |
| 功能丰富性 | 支持更多IPC功能(如消息队列、信号量) | 专注于共享内存,接口更简单 |
| 性能 | 较高 | 较高,但可能因实现差异略有不同 |
| 易用性 | 需要管理键值和权限 | 路径名更直观,权限控制更灵活 |
| 典型应用场景 | 需要与其他System V IPC机制配合使用的场景 | 需要与其他POSIX IPC机制配合使用的场景 |
| 开发复杂度 | 中等 | 较低,API更直观 |
| 错误处理 | 需要检查返回值和errno | 同样需要检查返回值和errno |
| 资源管理 | 需要手动管理键值和权限 | 路径名更直观,但仍需注意资源释放 |
| 兼容性 | 广泛支持于各种Unix-like系统 | 主要支持于支持POSIX标准的系统 |
| 扩展性 | 可以与其他System V IPC机制结合使用 | 可以与其他POSIX IPC机制结合使用 |
| 开发效率 | 可能需要更多代码来处理键值和权限 | API更简洁,开发效率更高 |
| 学习曲线 | 较陡峭,需要理解System V IPC机制 | 较平缓,API设计更符合现代编程习惯 |
| 社区支持 | 广泛,历史悠久 | 逐渐增加,特别是在现代系统中 |
| 文档和示例 | 丰富,但可能较为分散 | 相对集中,易于查找 |
| 调试难度 | 中等,需要理解IPC机制 | 较低,API更直观 |
| 维护成本 | 中等,需要管理键值和权限 | 较低,路径名更直观,权限控制更灵活 |
| 性能优化 | 可以通过调整系统参数进行优化 | 同样可以通过调整系统参数进行优化 |
| 安全性 | 需要正确设置权限以避免安全风险 | 同样需要正确设置权限以避免安全风险 |
| 跨平台支持 | 有限,主要在Unix-like系统中 | 较好,符合POSIX标准,跨平台更好 |
| 开发工具支持 | 广泛支持于各种开发工具和环境 | 同样支持于各种开发工具和环境 |
| 未来发展趋势 | 逐渐被POSIX共享内存取代 | 逐渐成为主流,特别是在现代系统中 |
| 典型问题 | 键值冲突、权限管理复杂 | 路径名冲突、权限管理相对简单 |
| 解决方案 | 使用唯一的键值,合理设置权限 | 使用唯一的路径名,合理设置权限 |
| 最佳实践 | 确保正确管理键值和权限,避免资源泄漏 | 确保正确管理路径名和权限,避免资源泄漏 |
| 性能考虑 | 高效,但需注意同步和锁机制 | 高效,同样需注意同步和锁机制 |
| 资源释放 | 需要手动调用shmdt和shmctl |
需要手动调用munmap和shm_unlink |
| 错误处理 | 需要检查返回值和errno | 同样需要检查返回值和errno |
| 开发效率 | 中等,需要编写较多代码 | 较高,API更简洁 |
| 学习资源 | 丰富,但可能较为分散 | 相对集中,易于查找 |
| 社区支持 | 广泛,历史悠久 | 逐渐增加,特别是在现代系统中 |
| 文档和示例 | 丰富,但可能较为分散 | 相对集中,易于查找 |
| 调试难度 | 中等,需要理解IPC机制 | 较低,API更直观 |
| 维护成本 | 中等,需要管理键值和权限 | 较低,路径名更直观,权限控制更灵活 |
| 性能优化 | 可以通过调整系统参数进行优化 | 同样可以通过调整系统参数进行优化 |
| 安全性 | 需要正确设置权限以避免安全风险 | 同样需要正确设置权限以避免安全风险 |
| 跨平台支持 | 有限,主要在Unix-like系统中 | 较好,符合POSIX标准,跨平台更好 |
| 开发工具支持 | 广泛支持于各种开发工具和环境 | 同样支持于各种开发工具和环境 |
| 未来发展趋势 | 逐渐被POSIX共享内存取代 | 逐渐成为主流,特别是在现代系统中 |
| 典型问题 | 键值冲突、权限管理复杂 | 路径名冲突、权限管理相对简单 |
| 解决方案 | 使用唯一的键值,合理设置权限 | 使用唯一的路径名,合理设置权限 |
| 最佳实践 | 确保正确管理键值和权限,避免资源泄漏 | 确保正确管理路径名和权限,避免资源泄漏 |
| 性能考虑 | 高效,但需注意同步和锁机制 | 高效,同样需注意同步和锁机制 |
| 资源释放 | 需要手动调用shmdt和shmctl |
需要手动调用munmap和shm_unlink |
| 错误处理 | 需要检查返回值和errno | 同样需要检查返回值和errno |
| 开发效率 | 中等,需要编写较多代码 | 较高,API更简洁 |
| 学习资源 | 丰富,但可能较为分散 | 相对集中,易于查找 |
| 社区支持 | 广泛,历史悠久 | 逐渐增加,特别是在现代系统中 |
| 文档和示例 | 丰富,但可能较为分散 | 相对集中,易于查找 |
| 调试难度 | 中等,需要理解IPC机制 | 较低,API更直观 |
| 维护成本 | 中等,需要管理键值和权限 | 较低,路径名更直观,权限控制更灵活 |
| 性能优化 | 可以通过调整系统参数进行优化 | 同样可以通过调整系统参数进行优化 |
| 安全性 | 需要正确设置权限以避免安全风险 | 同样需要正确设置权限以避免安全风险 |
| 跨平台支持 | 有限,主要在Unix-like系统中 | 较好,符合POSIX标准,跨平台更好 |
| 开发工具支持 | 广泛支持于各种开发工具和环境 | 同样支持于各种开发工具和环境 |
| 未来发展趋势 | 逐渐被POSIX共享内存取代 | 逐渐成为主流,特别是在现代系统中 |
| 典型问题 | 键值冲突、权限管理复杂 | 路径名冲突、权限管理相对简单 |
| 解决方案 | 使用唯一的键值,合理设置权限 | 使用唯一的路径名,合理设置权限 |
| 最佳实践 | 确保正确管理键值和权限,避免资源泄漏 | 确保正确管理路径名和权限,避免资源泄漏 |
| 性能考虑 | 高效,但需注意同步和锁机制 | 高效,同样需注意同步和锁机制 |
| 资源释放 | 需要手动调用shmdt和shmctl |
需要手动调用munmap和shm_unlink |
| 错误处理 | 需要检查返回值和errno | 同样需要检查返回值和errno |
| 开发效率 | 中等,需要编写较多代码 | 较高,API更简洁 |
| 学习资源 | 丰富,但可能较为分散 | 相对集中,易于查找 |
| 社区支持 | 广泛,历史悠久 | 逐渐增加,特别是在现代系统中 |
| 文档和示例 | 丰富,但可能较为分散 | 相对集中,易于查找 |
| 调试难度 | 中等,需要理解IPC机制 | 较低,API更直观 |
| 维护成本 | 中等,需要管理键值和权限 | 较低,路径名更直观,权限控制更灵活 |
| 性能优化 |
