基于fork与共享内存的斐波那契生成器程序调试求助
父子进程共享内存通信卡死问题分析与修复
问题背景
需实现程序:主进程从命令行获取参数n(n<40),创建共享内存(大小为BUF_SZ*sizeof(unsigned short),BUF_SZ=5)和子进程;子进程从父进程获取n,生成长度为n的unsigned short类型斐波那契序列,每生成一个元素后等待0-2秒随机时间再放入共享内存;父进程立即打印共享内存中的元素,无需等待子进程退出。当前代码父进程陷入无限循环,无法切换到子进程。
原代码核心问题
- 共享内存名称冲突:创建
outptr的共享内存时误用了NAME2(与inptr的共享内存同名),导致inptr和outptr指向同一块内存,初始值均为0,父进程的while (*inptr == *outptr)条件永远成立,陷入死循环。 - 主函数参数未声明:
main()未定义argc和argv参数,直接访问argv[1]会触发未定义行为。 - 父进程读取逻辑不完整:仅读取一次元素就退出,未循环读取所有n个斐波那契元素。
- 子进程斐波那契生成逻辑错误:循环内重复写入元素,且循环条件
i <=n会生成n+1个元素,不符合要求。 - 缺少随机等待逻辑:未实现子进程生成元素后等待0-2秒的需求。
- 资源未清理:未删除共享内存对象,会残留系统资源。
修复后的代码
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <sys/mman.h> #include <fcntl.h> #include <errno.h> #include <sys/wait.h> #define BUF_SZ 5 #define NAME "buffer" #define NAME_INPTR "inptr" #define NAME_OUTPTR "outptr" int main(int argc, char *argv[]) { // 命令行参数合法性检查 if (argc != 2) { fprintf(stderr, "Usage: %s <n>\n", argv[0]); exit(EXIT_FAILURE); } int n = atoi(argv[1]); if (n >= 40 || n <= 0) { fprintf(stderr, "n must be positive and less than 40\n"); exit(EXIT_FAILURE); } int fd[2]; unsigned short *data; int* inptr; int* outptr; int size_data = BUF_SZ * sizeof(unsigned short); int size_ptr = sizeof(int); // 创建数据共享内存 int shmid_data = shm_open(NAME, O_CREAT|O_RDWR, 0666); if (shmid_data == -1) { perror("shm_open data"); exit(EXIT_FAILURE); } if (ftruncate(shmid_data, size_data) == -1) { perror("ftruncate data"); exit(EXIT_FAILURE); } data = (unsigned short*) mmap(NULL, size_data, PROT_READ|PROT_WRITE, MAP_SHARED, shmid_data, 0); if (data == MAP_FAILED) { perror("mmap data"); exit(EXIT_FAILURE); } // 创建inptr共享内存 int shmid_in = shm_open(NAME_INPTR, O_CREAT|O_RDWR, 0666); if (shmid_in == -1) { perror("shm_open inptr"); exit(EXIT_FAILURE); } if (ftruncate(shmid_in, size_ptr) == -1) { perror("ftruncate inptr"); exit(EXIT_FAILURE); } inptr = (int*) mmap(NULL, size_ptr, PROT_READ|PROT_WRITE, MAP_SHARED, shmid_in, 0); if (inptr == MAP_FAILED) { perror("mmap inptr"); exit(EXIT_FAILURE); } // 创建outptr共享内存(修复名称冲突问题) int shmid_out = shm_open(NAME_OUTPTR, O_CREAT|O_RDWR, 0666); if (shmid_out == -1) { perror("shm_open outptr"); exit(EXIT_FAILURE); } if (ftruncate(shmid_out, size_ptr) == -1) { perror("ftruncate outptr"); exit(EXIT_FAILURE); } outptr = (int*) mmap(NULL, size_ptr, PROT_READ|PROT_WRITE, MAP_SHARED, shmid_out, 0); if (outptr == MAP_FAILED) { perror("mmap outptr"); exit(EXIT_FAILURE); } // 初始化读写指针 *inptr = 0; *outptr = 0; // 创建管道用于传递n值 if (pipe(fd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } pid_t pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (pid > 0) { // 父进程逻辑 close(fd[0]); // 关闭管道读端 write(fd[1], &n, sizeof(n)); close(fd[1]); // 循环读取n个斐波那契元素 for (int i = 0; i < n; i++) { // 等待缓冲区有可用数据 while (*inptr == *outptr); printf("%hu\n", data[*outptr]); fflush(stdout); *outptr = (*outptr + 1) % BUF_SZ; } // 释放父进程资源 munmap(data, size_data); close(shmid_data); munmap(inptr, size_ptr); close(shmid_in); munmap(outptr, size_ptr); close(shmid_out); // 等待子进程退出后清理共享内存 wait(NULL); shm_unlink(NAME); shm_unlink(NAME_INPTR); shm_unlink(NAME_OUTPTR); } else if (pid == 0) { // 子进程逻辑 close(fd[1]); // 关闭管道写端 read(fd[0], &n, sizeof(n)); close(fd[0]); srand(time(NULL)); // 初始化随机数种子 unsigned short prev = 0; unsigned short curr = 1; // 生成长度为n的斐波那契序列 for (int i = 0; i < n; i++) { // 等待缓冲区有空位 while (((*inptr + 1) % BUF_SZ) == *outptr); if (i == 0) { data[*inptr] = prev; } else if (i == 1) { data[*inptr] = curr; } else { unsigned short next = prev + curr; data[*inptr] = next; prev = curr; curr = next; } *inptr = (*inptr + 1) % BUF_SZ; // 随机等待0-2秒 sleep(rand() % 3); } // 释放子进程资源 munmap(data, size_data); close(shmid_data); munmap(inptr, size_ptr); close(shmid_in); munmap(outptr, size_ptr); close(shmid_out); exit(EXIT_SUCCESS); } return 0; }
修复说明
- 修正共享内存名称:为
inptr和outptr分配独立的共享内存名称,避免指针指向同一块内存导致的死循环。 - 完善参数处理:添加
argc和argv参数声明,补充命令行参数合法性检查。 - 修复父进程读取逻辑:循环读取n次元素,确保输出所有生成的斐波那契数。
- 修正斐波那契生成逻辑:调整循环逻辑,准确生成n个元素,避免重复写入问题。
- 添加随机等待:通过
srand和sleep实现0-2秒的随机等待功能。 - 资源清理:添加共享内存的卸载、关闭和删除操作,避免系统资源泄漏。
- 错误处理:为所有系统调用添加错误检查,便于排查运行时问题。
内容的提问来源于stack exchange,提问作者ProgrammerNoob
相关产品推荐
相关产品推荐

