You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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;
}

修复说明

  1. 修正共享内存名称:为inptr和outptr分配独立的共享内存名称,避免指针指向同一块内存导致的死循环。
  2. 完善参数处理:添加argc和argv参数声明,补充命令行参数合法性检查。
  3. 修复父进程读取逻辑:循环读取n次元素,确保输出所有生成的斐波那契数。
  4. 修正斐波那契生成逻辑:调整循环逻辑,准确生成n个元素,避免重复写入问题。
  5. 添加随机等待:通过srand和sleep实现0-2秒的随机等待功能。
  6. 资源清理:添加共享内存的卸载、关闭和删除操作,避免系统资源泄漏。
  7. 错误处理:为所有系统调用添加错误检查,便于排查运行时问题。

内容的提问来源于stack exchange,提问作者ProgrammerNoob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 13:58:13