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
相关产品推荐
相关产品推荐

