循环Fork进程时进程编号打印异常及CPU/IO密集型任务实现问题
问题分析与修复方案
问题1:进程完成信息重复打印
你的代码中,所有子进程和父进程都会执行最后的等待循环,导致打印次数远超N次。正确逻辑应该是:
- 子进程完成任务后直接退出,不参与等待和打印
- 仅由父进程负责等待所有子进程,并打印每个进程的完成信息
另外,原cpuNum和ioNum的分配逻辑错误:fork后每个子进程拥有独立的变量副本,无法通过cpuNum--来分配任务,应该在创建子进程时,根据循环序号n直接指定该进程是CPU密集型还是IO密集型。
问题2:CPU/IO密集型伪工作的正确性
- CPU密集型:用
volatile修饰循环变量的写法是对的,能防止编译器优化空循环,确保进程持续占用CPU资源。可通过调整循环次数控制CPU工作时长。 - IO密集型:
sleep(200)只是让进程休眠,没有实际IO操作,不属于真正的IO密集型任务。应模拟频繁IO行为,比如反复读写文件(如/dev/null),这样才会产生真实的IO负载。
修正后的代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <stdint.h> #include <fcntl.h> #include <string.h> // 假设waitStats函数实现(需根据实际需求完善) int waitStats(int options, uint32_t *rtime, uint32_t *wtime) { pid_t pid = waitpid(-1, NULL, options); if (pid == -1) return -1; // 示例赋值,实际需通过rusage等系统调用计算真实时间 *rtime = 100; *wtime = 50; return pid; } int main(int argc, char* argv[]) { // 参数格式检查:需传入 -c <CPU进程数> -i <IO进程数> if (argc != 5 || strcmp(argv[1], "-c") != 0 || strcmp(argv[3], "-i") != 0) { fprintf(stderr, "用法: %s -c <cpu_num> -i <io_num>\n", argv[0]); exit(EXIT_FAILURE); } int cpuNum = atoi(argv[2]); int ioNum = atoi(argv[4]); const int MAX_PROC = cpuNum + ioNum; printf("\n总进程数: %d\n", MAX_PROC); int totRunTime = 0; int totWaitTime = 0; uint32_t rTime = 0; uint32_t wTime = 0; // 创建子进程 for (int n = 0; n < MAX_PROC; n++) { pid_t pid = fork(); if (pid == -1) { perror("fork失败"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程:根据序号分配任务类型 if (n < cpuNum) { printf("子进程 %d (PID: %d) 开始CPU密集型任务\n", n, getpid()); // CPU密集型:空循环(volatile防止编译器优化) for (volatile int i = 0; i < 1000000000; i++); } else { printf("子进程 %d (PID: %d) 开始IO密集型任务\n", n, getpid()); // IO密集型:反复写入/dev/null模拟IO负载 int fd = open("/dev/null", O_WRONLY); if (fd == -1) { perror("打开/dev/null失败"); exit(EXIT_FAILURE); } char buf[1024]; memset(buf, 'a', sizeof(buf)); for (int i = 0; i < 1000; i++) { write(fd, buf, sizeof(buf)); } close(fd); // 也可用多次短休眠模拟IO等待:for (int i=0; i<200; i++) usleep(1000); } // 子进程完成任务后直接退出,不执行后续代码 exit(EXIT_SUCCESS); } // 父进程继续创建下一个子进程 } // 仅父进程执行:等待所有子进程并统计信息 printf("\n父进程等待子进程完成...\n"); for (int p = 0; p < MAX_PROC; p++) { if (waitStats(0, &rTime, &wTime) >= 0) { printf("进程 %d 完成 | 运行时间: %u, 等待时间: %u\n", p, rTime, wTime); totRunTime += rTime; totWaitTime += wTime; } } // 计算并打印平均时间 if (MAX_PROC > 0) { printf("\n平均运行时间: %d, 平均等待时间: %d\n", totRunTime / MAX_PROC, totWaitTime / MAX_PROC); } exit(EXIT_SUCCESS); }
关键修复点说明
- 任务分配逻辑:通过循环序号直接指定子进程任务类型,避免变量副本导致的分配错误。
- 子进程退出逻辑:子进程完成任务后立即
exit,确保只有父进程执行等待和打印操作。 - IO任务修正:替换
sleep为实际文件写入操作,真实模拟IO负载;也可根据需求改用短时间多次休眠。 - 参数检查:增加命令行参数格式校验,避免非法输入导致崩溃。
内容的提问来源于stack exchange,提问作者Stravvberry_Milk
相关产品推荐
相关产品推荐

