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

如何用循环创建多子进程并实现两子进程依次处理不同文件?

问题分析与解决方案

原代码的核心问题是:循环创建子进程后,两个子进程会同时启动并尝试读取标准输入,而所有进程共享同一个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;
}

关键修正点:

  1. 信号处理函数仅设置标志位,不在信号上下文执行printf这类不安全的IO操作
  2. 子进程用循环等待信号,避免被其他信号意外唤醒
  3. 处理fgets被信号中断的错误,重新尝试读取
  4. 父进程清空输入缓冲,避免之前的换行符导致操作被跳过

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 13:43:16