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更直观 |
维护成本 | 中等,需要管理键值和权限 | 较低,路径名更直观,权限控制更灵活 |
性能优化 |
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/55134.html