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

Linux下父子进程不使用pipe通过共享内存实现异步通信的作业实现问题

问题核心与修改方案

你当前代码的核心问题是父进程调用wait()阻塞等待子进程完全退出后才统一打印所有结果,不符合作业要求的「父进程不等待子进程退出、有新元素就立即打印」的异步通信要求。同时共享内存没有写入进度标记,父进程无法感知新元素生成。

修改要点

  • 在共享内存中新增一个写入进度计数器:我们约定shared_memory[2]存储子进程已成功写入的元素数量,初始值为0。子进程每生成一个元素写入共享内存后,将该计数器加1。
  • 父进程移除wait()阻塞逻辑,改为轮询该进度计数器:父进程维护一个本地已打印计数变量,只要共享内存中的进度计数器大于本地已打印计数,就打印新生成的元素,直到所有n个元素全部打印完成。
  • 补充随机数种子初始化:子进程入口处调用srand(time(NULL) ^ getpid()),保证每次运行生成的随机休眠时长不同,同时避免父子进程随机种子重复。
  • 所有printf后添加fflush(stdout),确保输出立即刷新到屏幕,符合作业要求。
  • 父进程打印完所有元素后再调用wait()回收子进程资源,避免产生僵尸进程。
  • 把原有的秒级休眠改为微秒级休眠,匹配作业要求的0到9.999秒随机间隔规则。

修改后完整代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>

// 子进程生成等差数列逻辑
void computeLab4(int n, int d, int *data_start, int *write_counter) {
    for (int i = 0; i < n; i++) {
        // 生成0-9999毫秒的随机休眠时长,符合0-9.999秒的要求
        int sleep_ms = rand() % 10000;
        printf("子进程:将休眠%d毫秒\n", sleep_ms);
        fflush(stdout);
        usleep(sleep_ms * 1000); // 微秒级休眠,匹配要求的随机精度
        
        data_start[i] = i * d;
        printf("子进程:生成第%d个元素,值为%d\n", i+1, data_start[i]);
        fflush(stdout);
        
        // 写入完成后更新计数器,告知父进程有新数据
        (*write_counter)++;
    }
}

int main(int argc, char *argv[]) {
    pid_t childPID;
    int shm_fd;
    int *shared_memory;
    int msize;
    const char *shm_name = "Lab_4";
    int n, d;

    if (argc != 3) {
        fprintf(stderr, "用法: %s <数列长度n> <公差d>\n", argv[0]);
        return -1;
    }

    n = atoi(argv[1]);
    d = atoi(argv[2]);

    if (n <= 0 || d < 0) {
        fprintf(stderr, "参数非法:n必须大于0,d不能为负\n");
        return -2;
    }

    // 共享内存布局:[0]存n, [1]存d, [2]存写入计数器, [3]开始存数列元素
    msize = (n + 3) * sizeof(int);

    // 创建共享内存
    shm_fd = shm_open(shm_name, O_CREAT | O_EXCL | O_RDWR, S_IRWXU | S_IRWXG);
    if (shm_fd < 0) {
        perror("shm_open失败");
        return -3;
    }

    ftruncate(shm_fd, msize);
    shared_memory = (int *)mmap(NULL, msize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shared_memory == MAP_FAILED) {
        perror("mmap失败");
        shm_unlink(shm_name);
        return -3;
    }

    // 初始化共享内存头信息
    shared_memory[0] = n;
    shared_memory[1] = d;
    shared_memory[2] = 0; // 写入计数器初始为0

    childPID = fork();
    if (childPID == -1) {
        perror("fork失败");
        shm_unlink(shm_name);
        return -4;
    }

    if (childPID == 0) {
        // 子进程逻辑
        srand(time(NULL) ^ getpid()); // 初始化随机数种子
        computeLab4(shared_memory[0], shared_memory[1], shared_memory + 3, &shared_memory[2]);
        exit(0);
    } else {
        // 父进程逻辑:轮询计数器打印新元素,不阻塞等待子进程退出
        int printed_count = 0;
        while (printed_count < n) {
            // 只要有新写入的元素就打印
            while (shared_memory[2] > printed_count) {
                printf("父进程:接收到第%d个元素,值为%d\n", printed_count + 1, shared_memory[3 + printed_count]);
                fflush(stdout);
                printed_count++;
            }
            // 每次轮询间隔1毫秒,避免CPU空转占用过高
            usleep(1000);
        }

        // 所有元素打印完成后回收子进程资源
        wait(NULL);
        // 清理共享内存
        shm_unlink(shm_name);
    }

    return 0;
}

编译运行说明

编译时需要链接共享内存相关的rt库:

gcc -o lab4 lab4.c -lrt

运行示例(生成5个元素、公差为2的等差数列):

./lab4 5 2

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 22:15:03