web-dev-qa-db-ja.com

fork()複数プロセスUnixのフォークの問題

したがって、N個の子プロセスをforkするこの関数があります。ただし、指定以上に分岐しているようです。私が間違っていることを教えてもらえますか?ありがとう

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
15
user69514

Fork()呼び出しは、実行を開始する新しいプロセスを生成しますまったく同じポイントでフォークが発生した場所。つまり、フォークが「2回戻る」ように見えます

ここで起こっていることは、fork()呼び出しが2回返されるため、親プロセスと子プロセスの両方がループを続け、新しいプロセスを生成し続けることです。次に、(元の親と子の両方の)各子が再びフォークし、プロセスの数が繰り返し2倍になります...

14

プロセスをforkすると、基本的にプロセスの2つの(ほぼ)正確なコピーが作成され、両方が実行を継続します。

つまり、何が起こっているのかというと、子自身が(出力を出力した後)自分のプロセス空間でループを継続しているということです同様に親がそれを行っているように。そして、実際、これらの子供たちもフォークしているので、孫たちもその時点から続けます。最終的に何人の子供が生まれるかを実際に計算するための公式はあると思いますが(おそらく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> _
15
paxdiablo

各子プロセスは、ループを取得して続行します。

つまり、子1が生成され、ループの反復#2などが続行されます。

プロセスがフォークされると、現在のプロセスのコピーが作成されます。結果の子プロセスは、fork()呼び出しの後も実行を継続します。そのため、ロジック内の戻りコードに注意する必要があります。

1
jldupont

この演習では、forループではなく再帰を使用します。このようにして、fork()命令を複数回呼び出すことができますが、プロセスの2つのコピーのうちの1つだけです。子プロセスに別の子プロセスを生成させて、祖父母、祖父母などを作成することも、単一の「父」と複数の子を持つ親側で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);
  }
}
1
singintime