Linux共享内存创建遇权限拒绝、段错误及映射失败问题求助
解决共享内存实现考拉兹猜想的权限、段错误和映射问题
嘿,作为Linux新手能尝试用共享内存实现跨进程通信已经很棒了!咱们来一步步拆解你代码里的坑,这些都是刚接触POSIX共享内存时很容易踩的:
1. 共享内存对象命名不符合规范
Linux下POSIX共享内存的名字必须以斜杠/开头,比如"/collatz_shm",你用的"name"不符合规则,这会直接导致shm_open触发权限拒绝或者找不到对象的问题。
2. 父进程shm_open未正确获取文件描述符
你在父进程里写了shm_open(obj,O_RDONLY,S_IRWXU);但完全没把返回值赋值给fd,fd还是初始的0(对应标准输入),用这个无效的文件描述符去调用mmap,不失败才怪!正确写法应该是:
fd = shm_open(obj, O_RDONLY, 0); // 只读打开不需要传mode参数 if (fd == -1) { perror("Parent shm_open error"); exit(EXIT_FAILURE); }
3. sprintf重复覆盖导致输出不全/段错误
你每次循环都用sprintf(ptr1,"%d, ",num);,这会一直覆盖共享内存的起始位置,最后只能看到序列的最后一个数。如果序列太长还会溢出共享内存,触发段错误。咱们得维护一个偏移量,每次追加内容:
// 子进程里初始化偏移量 size_t offset = 0; // 先写入初始数字 offset += snprintf((char*)ptr1 + offset, page_size - offset, "%d, ", num); while(num != 1) { if(num%2 == 0) num = num / 2; else num = (num * 3) + 1; // 用snprintf确保不会溢出共享内存 ssize_t written = snprintf((char*)ptr1 + offset, page_size - offset, "%d, ", num); if(written < 0) break; offset += written; if(offset >= page_size) { printf("共享内存不够用啦,提前停止\n"); break; } }
4. 缺少关键的错误检查和资源清理
- 所有
shm_open、mmap、ftruncate调用都要检查返回值,用perror打印具体错误,不然出问题根本不知道哪里错了 - 使用完共享内存文件描述符后要调用
close(fd),避免资源泄漏 - 子进程和父进程
mmap后都要调用munmap释放映射的内存 - 父进程
mmap后要检查是否返回MAP_FAILED,别硬着头皮继续操作
修正后的完整代码
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<fcntl.h> #include<sys/mman.h> #include<sys/wait.h> #include<sys/stat.h> #include<string.h> int main(int argc,char** argv) { pid_t pid; pid = fork(); const size_t page_size = 4096; // 共享内存名必须以/开头 const char* obj = "/collatz_shm"; int num; if(argc < 2) { printf("请传入一个正整数作为参数\n"); return EXIT_FAILURE; } num = atoi(argv[1]); if(num < 1) { printf("请输入大于0的数字\n"); return EXIT_FAILURE; } if(pid < 0) { perror("Fork失败"); return EXIT_FAILURE; } else if(pid == 0) { // 创建共享内存,权限设为所有者读写 int fd1 = shm_open(obj, O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (fd1 == -1) { perror("子进程shm_open错误"); exit(EXIT_FAILURE); } if(ftruncate(fd1, page_size) == -1) { perror("ftruncate设置共享内存大小错误"); close(fd1); shm_unlink(obj); exit(EXIT_FAILURE); } void *ptr1 = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, fd1, 0); if(ptr1 == MAP_FAILED) { perror("子进程mmap失败"); close(fd1); shm_unlink(obj); exit(EXIT_FAILURE); } size_t offset = 0; // 写入初始数字 offset += snprintf((char*)ptr1 + offset, page_size - offset, "%d, ", num); while(num != 1) { if(num%2 == 0) num = num / 2; else num = (num * 3) + 1; // 追加数字,确保不溢出 ssize_t written = snprintf((char*)ptr1 + offset, page_size - offset, "%d, ", num); if(written < 0) break; offset += written; if(offset >= page_size) { printf("共享内存已满,提前停止计算\n"); break; } } // 子进程清理资源 munmap(ptr1, page_size); close(fd1); exit(EXIT_SUCCESS); } else { // 等待子进程完成计算 wait(NULL); int fd = shm_open(obj, O_RDONLY, 0); if (fd == -1) { perror("父进程shm_open错误"); return EXIT_FAILURE; } void *ptr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); if(ptr == MAP_FAILED) { perror("父进程mmap失败"); close(fd); shm_unlink(obj); return EXIT_FAILURE; } printf("考拉兹序列: %s\n", (char*)ptr); // 父进程清理资源 munmap(ptr, page_size); close(fd); shm_unlink(obj); } return EXIT_SUCCESS; }
编译运行说明
编译时需要链接rt库(POSIX共享内存属于实时扩展库):
gcc collatz_shm.c -o collatz_shm -lrt
运行时传入一个正整数参数:
./collatz_shm 10
这样就能解决你遇到的权限拒绝、段错误和映射失败问题,正常输出考拉兹序列啦!
内容的提问来源于stack exchange,提问作者Shary
相关产品推荐
相关产品推荐

