如何用循环创建多子进程并实现两子进程依次处理不同文件?
问题分析与解决方案
原代码的核心问题是:循环创建子进程后,两个子进程会同时启动并尝试读取标准输入,而所有进程共享同一个stdin/stdout流,导致提示信息和输入操作交织混乱,无法按顺序处理文件。
方案一:逐个创建并等待子进程(最简单高效)
直接让父进程创建一个子进程后,立即等待它完成输入操作,再创建下一个子进程,从根本上避免并发IO冲突:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/wait.h> int main() { pid_t pids[2]; char nomefile[256]; char buffer[256]; int fd; for(int i = 0; i < 2; i++){ if((pids[i] = fork()) < 0){ fprintf(stderr, "创建子进程%d失败\n", i+1); exit(EXIT_FAILURE); } if(pids[i] == 0){ sprintf(nomefile, "file_figlio_%d.txt", i+1); fd = open(nomefile, O_CREAT | O_TRUNC | O_WRONLY, 0660); if(fd < 0){ perror("打开文件失败"); exit(EXIT_FAILURE); } printf("请输入文件%d的内容:\n", i+1); fgets(buffer, sizeof(buffer), stdin); write(fd, buffer, strlen(buffer)); close(fd); exit(EXIT_SUCCESS); } // 父进程等待当前子进程执行完毕,再创建下一个 waitpid(pids[i], NULL, 0); } return 0; }
方案二:提前创建所有子进程,用信号顺序唤醒(针对你的修正思路优化)
如果需要先创建所有子进程再触发输入,需要解决信号处理、IO中断和输入缓冲的问题,修正后的代码如下:
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/wait.h> #include <errno.h> volatile sig_atomic_t sig_received = 0; // 信号处理函数仅设置标志,避免在信号上下文执行IO操作 void sig_handler(int sig){ sig_received = 1; } int main(){ int n = 2; pid_t pid[2]; char nomefile[256]; char buffer[256]; struct sigaction action; // 注册SIGUSR1信号处理函数 action.sa_handler = sig_handler; sigemptyset(&action.sa_mask); action.sa_flags = 0; sigaction(SIGUSR1, &action, NULL); for(int i = 0; i < n;i++){ if((pid[i] = fork()) < 0){ fprintf(stderr, "创建子进程失败\n"); exit(EXIT_FAILURE); } if(pid[i] == 0){ // 循环等待信号,避免被其他信号意外中断 while(!sig_received){ pause(); } sprintf(nomefile, "figlio_mag%d.txt", i+1); int fd = open(nomefile, O_CREAT | O_WRONLY | O_TRUNC, 0660); if(fd < 0){ perror("打开文件失败"); exit(EXIT_FAILURE); } printf("请输入文件%d的内容:\n", i+1); // 处理fgets被信号中断的情况,重新尝试读取 while(fgets(buffer, sizeof(buffer), stdin) == NULL && ferror(stdin) && errno == EINTR){ clearerr(stdin); } write(fd, buffer, strlen(buffer)); close(fd); exit(EXIT_SUCCESS); } } for(int i = 0; i < n; i++){ printf("父进程:按回车开始输入文件%d的内容\n", i+1); // 清空输入缓冲,避免残留字符导致直接跳过 while(getchar() != '\n'); kill(pid[i], SIGUSR1); waitpid(pid[i], NULL, 0); } return 0; }
关键修正点:
- 信号处理函数仅设置标志位,不在信号上下文执行
printf这类不安全的IO操作 - 子进程用循环等待信号,避免被其他信号意外唤醒
- 处理
fgets被信号中断的错误,重新尝试读取 - 父进程清空输入缓冲,避免之前的换行符导致操作被跳过
内容的提问来源于stack exchange,提问作者Vittorio
相关产品推荐
相关产品推荐

