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

如何确保子进程在父进程完成创建循环后才执行?

如何让父进程完成所有创建输出后再启动子进程执行逻辑

我用C语言写了一个for循环来创建指定数量的进程,父进程分支(pid>0)和子进程分支(pid==0)都在循环内,wait()调用放在循环结束后。目前存在问题:部分子进程会在父进程仍处于循环执行阶段时就输出fprintf内容,且子进程启动顺序随机。需要确保父进程完成整个循环及所有输出后,子进程才开始执行各自的逻辑。

执行命令./a.out 5 process 1后,输出对比如下:

输出对比

预期输出

Process 0 creating process 1...
Process 0 creating process 2...
Process 0 creating process 3...
Process 0 creating process 4...
Process 0 creating process 5...
Process 1 beginning...
*(随机时长休眠)*
Process 1 ending...
Process 2 beginning...
*(随机时长休眠)*
Process 2 ending...
Process 3 beginning...
*(随机时长休眠)*
Process 3 ending...
Process 4 beginning...
*(随机时长休眠)*
Process 4 ending...
Process 5 beginning...
*(随机时长休眠)*
Process 5 ending...

实际输出

Process 0 creating process 1...
Process 1 beginning...
Process 0 creating process 2...
Process 2 beginning...
Process 0 creating process 3...
Process 0 creating process 4...
Process 0 creating process 5...
Process 5 beginning...
Process 3 beginning...
Process 4 beginning...
*(随机时长休眠)*
Process 1 ending...
Process 2 ending...
Process 5 ending...
Process 3 ending...
Process 4 ending...

现有代码

main.c

/*
 * Write a program that takes three arguments:
 * the number of “things” (between 1 and 256),
 * a word: either “thread” or “process, and
 * a “pattern number” (1-2 only).
 */
#include "functions.c"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

// USE STDERR FOR PRINTING
// fprintf(stderr, "This is process %d \n", getpid());

// extern set_pattern

typedef struct {
  int number;
  pid_t pid;
} process;

typedef struct {
  int number;
  pthread_t tid;
} thread;

int main(int argc, char *argv[]) {
  setbuf(stdout, NULL);

  // Check for correct amount of paramters
  if (argc != 4) {
    help_and_exit(argv[0]);
  }
  // Parse parameters and check for errors

  // Set size
  int size;
  set_size(argv, &size);

  // Set type (thread or process)
  exec_t type;
  set_choice(argv, &type);

  // Set pattern
  int pattern;
  set_pattern(argv, &pattern);

  // printf("Size is %d, choice is %d, and pattern is %d\n", size, type,
  // pattern);

  if (pattern == 1) {
    if (type == Process) {
      // process processes[size];
      pid_t alpha_process = getpid();
      int process_number = 0;

      pid_t pids[size];
      int n = size;
      int flag = 0;

      for (int i = 0; i < n; i++) {
        fflush(stdout);
        if ((pids[i] = fork()) < 0) {
          perror("fork");
        } else if (pids[i] == 0) {
          fprintf(stderr, "Process %d beginning...\n", i + 1);
          sleep(rand() % 5);
          fflush(stdout);
          fprintf(stderr, "Process %d ending...\n", i + 1);
          exit(0);
        } else if (pids[i] > 0) {
          fprintf(stderr, "Process %d creating process %d...\n", i - i, i + 1);
        }
      }

      int counter = 0;
      while (counter < n) {
        wait(NULL);
        counter++;
      }
    }
  }
  return 0;
}

functions.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

typedef enum { Thread, Process } exec_t;

void help_and_exit(char *name) {
  fprintf(stderr,
          "usage: %s <number of things> {thread | process} <pattern number>\n",
          name);
  exit(-1);
}

void set_size(char *argv[], int *size) {
  if (sscanf(argv[1], "%d", size) == 0) {
    fprintf(stderr, "First parameter must be an integer. Recieved: '%s'\n",
            argv[1]);
    help_and_exit(argv[0]);
  }
  if (*size > 256 || *size < 1) {
    fprintf(stderr, "Number of things must be between 1-256!\n");
    help_and_exit(argv[0]);
  }
}

void set_choice(char *argv[], exec_t *type) {
  char choice[8];
  if (sscanf(argv[2], "%s", choice) == 0) {
    fprintf(stderr, "Second parameter must be a string. Recieved: '%s'\n",
            argv[2]);
    help_and_exit(argv[0]);
  }
  if (strcmp(choice, "thread") != 0 && strcmp(choice, "process") != 0) {
    fprintf(stderr, "Second parameter must be either 'thread' or 'process'\n");
    help_and_exit(argv[0]);
  } else if (strcmp(choice, "thread") == 0) {
    *type = Thread;
  } else {
    *type = Process;
  }
}
void set_pattern(char *argv[], int *pattern) {
  if (sscanf(argv[3], "%d", pattern) == 0) {
    fprintf(stderr, "Third parameter must be an integer. Recieved: '%s'\n",
            argv[3]);
    help_and_exit(argv[0]);
  }
  if (*pattern != 1 && *pattern != 2) {
    fprintf(stderr, "Pattern number must be either 1 or 2!\n");
    help_and_exit(argv[0]);
  }
}

解决方案

问题根源是fork()后子进程会立即被操作系统调度执行,与父进程抢占CPU时间片。要实现父进程完成所有创建输出后再启动子进程,可通过管道实现进程间同步,这是最简单的方案:

修改思路

  1. 父进程在创建子进程前,先创建一个匿名管道。
  2. 每个子进程被创建后,先尝试从管道读取数据(管道无数据时会阻塞)。
  3. 父进程完成所有创建输出后,向管道写入任意数据,触发所有子进程的读取操作结束,开始执行自身逻辑。

修改后的main.c关键代码

替换原有的Process分支逻辑:

if (pattern == 1) {
  if (type == Process) {
    pid_t pids[size];
    int n = size;
    int pipe_fd[2];
    
    // 创建匿名管道
    if (pipe(pipe_fd) == -1) {
      perror("pipe");
      exit(EXIT_FAILURE);
    }

    for (int i = 0; i < n; i++) {
      fflush(stderr); // 确保父进程输出立即刷新,避免缓存问题
      if ((pids[i] = fork()) < 0) {
        perror("fork");
      } else if (pids[i] == 0) {
        close(pipe_fd[1]); // 子进程关闭管道写端
        char dummy;
        read(pipe_fd[0], &dummy, 1); // 阻塞等待父进程信号
        close(pipe_fd[0]);
        
        fprintf(stderr, "Process %d beginning...\n", i + 1);
        sleep(rand() % 5);
        fprintf(stderr, "Process %d ending...\n", i + 1);
        exit(0);
      } else if (pids[i] > 0) {
        fprintf(stderr, "Process %d creating process %d...\n", 0, i + 1);
      }
    }

    // 父进程完成所有创建,发送唤醒信号
    close(pipe_fd[0]); // 关闭管道读端
    write(pipe_fd[1], "1", 1); // 写入一个字节,唤醒所有子进程
    close(pipe_fd[1]);

    int counter = 0;
    while (counter < n) {
      wait(NULL);
      counter++;
    }
  }
}

说明

  • 管道的read()操作在无数据时会阻塞,子进程会卡在该步骤直到父进程写入数据。
  • 父进程完成所有创建输出后,向管道写入数据,所有子进程会被唤醒并开始执行后续逻辑。
  • 必须在父进程和子进程中正确关闭管道的无用端,避免资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 14:20:59