问叉()多个进程Unix

时间:2009-11-03 02:02:25

标签: c process fork

所以我有这个函数可以分配N个子进程。然而,似乎分叉超过指定。你能告诉我我做错了什么吗? 感谢

void forkChildren(int nChildren){
    int i;
    for(i = 1; i <= nChildren; i++){
        pid = fork();
        if(pid == 0)          
            printf("I'm a child: %d PID: %d\n",i, getpid());
    }

} 

主要是我打电话:

forkChildren(5);

我期待以下输出:

I'm a child: 1 PID: 2990
I'm a child: 2 PID: 2991
I'm a child: 3 PID: 2992
I'm a child: 4 PID: 2993
I'm a child: 5 PID: 2994

但我得到以下内容:

I'm a child: 1 PID: 2990
I'm a child: 2 PID: 2991
I'm a child: 3 PID: 2992
I'm a child: 4 PID: 2993
I'm a child: 5 PID: 2994
user@computer:~/directory/$ I'm a child: 2 PID: 2999
I'm a child: 3 PID: 3000
I'm a child: 3 PID: 3001
I'm a child: 4 PID: 3002
I'm a child: 5 PID: 3003
I'm a child: 5 PID: 3004
I'm a child: 4 PID: 3005
I'm a child: 5 PID: 3006
I'm a child: 4 PID: 3007
I'm a child: 5 PID: 3008
I'm a child: 3 PID: 3011
I'm a child: 4 PID: 3012
I'm a child: 4 PID: 3010
I'm a child: 5 PID: 3013
I'm a child: 5 PID: 3014
I'm a child: 5 PID: 3015
I'm a child: 4 PID: 3018
I'm a child: 5 PID: 3019
I'm a child: 5 PID: 3020
I'm a child: 5 PID: 3021
I'm a child: 5 PID: 3023
I'm a child: 5 PID: 3025
I'm a child: 5 PID: 3024
I'm a child: 4 PID: 3022
I'm a child: 5 PID: 3026
I'm a child: 5 PID: 3027

4 个答案:

答案 0 :(得分:15)

当你fork一个过程时,你基本上会得到两个(几乎)精确的过程副本,并且它们都会继续运行。

所发生的事情是,孩子们自己在自己的处理空间中继续循环(在他们打印输出之后)以及作为父母这样做。而且,事实上,因为这些孩子也在分叉,孙子孙女也将继续从那时起。我确定有一个公式可以确定你最终得到了多少孩子(可能是N!)但我现在没有精力解决这个问题。最好使用以下解决方案。

告诉父母和孩子之间差异的方法是fork的返回值。

  • 如果你回到-1,你就是父母而fork失败了。
  • 如果你回到零,你就是孩子。
  • 如果你得到一个正数,你就是父母,那个数字就是孩子的PID(所以你可以操纵它或wait为它)。

这是一些测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void forkChildren (int nChildren) {
    int i;
    pid_t pid;
    for (i = 1; i <= nChildren; i++) {
        pid = fork();
        if (pid == -1) {
            /* error handling here, if needed */
            return;
        }
        if (pid == 0) {
            printf("I am a child: %d PID: %d\n",i, getpid());
            sleep (5);
            return;
        }
    }
}

int main (int argc, char *argv[]) {
    if (argc < 2) {
        forkChildren (2);
    } else {
        forkChildren (atoi (argv[1]));
    }
    return 0;
}

和一些输出显示正在发生的事情:

pax> forktest 5
I am a child: 1 PID: 4188
I am a child: 2 PID: 4180
I am a child: 3 PID: 5396
I am a child: 4 PID: 4316
I am a child: 5 PID: 4260

pax> _

答案 1 :(得分:14)

fork()调用产生一个新进程,该进程在发生fork的完全相同的点处开始执行。所以,看起来像fork“返回两次”

这里发生的是fork()调用返回两次,因此父进程和子进程都继续循环并生成新进程。然后每个孩子(原始父母和孩子)再次分叉,反复加倍进程数量......

答案 2 :(得分:1)

每个子进程都会启动并继续循环。

换句话说,生成子1并继续循环#2的迭代#。

当进程分叉时,会生成当前进程的副本:生成的子进程在fork()调用后继续执行。这就是你必须在逻辑中处理返回代码的原因。

答案 3 :(得分:1)

在本练习中,我将使用递归而不是for循环。这样,您可以多次调用fork()指令,但只能在该进程的两个副本之一上执行。你可以让子进程产生另一个子进程,因此有祖父母,曾祖父母等,或者你可以在父方调用fork(),只有一个“父”和多个子进程。这是实现后一种解决方案的代码示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int nChildren;

void myFork(int n);

int main(int argc, char *argv[]) {

  // just a check on the number of arguments supplied
  if (argc < 2) {
    printf("Usage: forktest <number_of_children>\n");
    printf("Example: forktest 5 - spawns 5 children processes\n");
    return -1;
  }

  nChildren = atoi(argv[1]);
  // starting the recursion...
  myFork(nChildren-1);
  return 0;
}

// the recursive function
void myFork(int n) {
  pid_t pid;

  pid = fork();

  // the child does nothing but printing a message on screen
  if (pid == 0) {
    printf("I am a child: %d PID: %d\n", nChildren-n, getpid());
    return;
  }

  // if pid != 0, we're in the parent
  // let's print a message showing that the parent pid is always the same...
  printf("It's always me (PID %d) spawning a new child (PID %d)\n", getpid(), pid);
  // ...and wait for the child to terminate.
  wait(pid);

  // let's call ourself again, decreasing the counter, until it reaches 0.
  if (n > 0) {
    myFork(n-1);
  }
}