Unix 上 fork() 多个进程的问题

发布于 2024-08-09 23:05:06 字数 1371 浏览 1 评论 0原文

所以我有这个函数可以分叉 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

So I have this function that forks N number of child processes. However it seems to be forking more than specified. Can you tell me what I'm doing wrong?
Thanks

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());
    }

} 

In main I call:

forkChildren(5);

I am expecting the following output:

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

But instead I get the following:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

会傲 2024-08-16 23:05:06

fork() 调用会生成一个新进程,该进程在分叉发生的同一点开始执行。因此,看起来 fork “返回两次”

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

The fork() call spawns a new process which begins its execution at the exact same point where the fork occurred. So, it looks like fork "returns twice"

What's happening here is that your fork() call returns twice, so both the parent and child process continue looping and spawning new processes. Each child (of both the original parent and child) then forks again, repeatedly doubling the number of processes...

撧情箌佬 2024-08-16 23:05:06

当您fork一个进程时,您基本上最终会得到该进程的两个(几乎)完全相同的副本,并且它们都将继续运行。

因此,发生的情况是,子进程本身在自己的进程空间中继续循环(在打印输出之后), 父进程也这样做。事实上,因为这些孩子也在分叉,所以孙子也将从这一点继续下去。我确信有一个公式可以实际计算出您最终会有多少个孩子(可能像 N!),但我现在没有精力计算出来。最好使用以下解决方案。

区分父级和子级的方法是通过 fork 的返回值。

  • 如果您返回 -1,则您是父级,并且 fork 失败。
  • 如果你得到零,你就是那个孩子。
  • 如果您返回一个正数,则您是父级,该数字是子级 PID(因此您可以操纵它或等待)。

这是一些测试代码:

#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> _

When you fork a process, you basically end up with two (almost) exact copies of the process and both of them will continue running.

So what's happening is that the children themselves are continuing the loop in the own process space (after they print their output) as well as the parent doing it. And, in fact, because these children are also forking, the grandchildren will also carry on from that point. I'm sure there's a formula for actually figuring out how many children you end up with (probably something like N!) but I don't have the energy to figure it out at the moment. Better to use the following solution.

The way to tell the difference between parent and child is the return value from fork.

  • If you get back a -1, you're the parent and the fork failed.
  • If you get back a zero, you're the child.
  • If you get back a positive number, you're the parent and that number is the child PID (so you can manipulate it or wait for it).

Here's some test code:

#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;
}

and some output to show you what's happening:

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> _
澜川若宁 2024-08-16 23:05:06

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

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

当进程被分叉时,会生成当前进程的副本:生成的子进程在 fork() 调用后继续执行。这就是为什么您必须注意逻辑中的返回代码。

Each child process picks up and continues the loop.

In other words, child 1 is spawned and continues with iteration #2 of loop etc.

When a process is forked, a copy of the current process is made: the resulting child process continues execution after the fork() call. That's why you must take care of the return code in your logic.

空气里的味道 2024-08-16 23:05:06

在本练习中,我将使用递归而不是 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);
  }
}

In this exercise I'd use recursion rather than a for loop. This way you can have the fork() instruction called multiple times but just on one of the two copies of the process. You can make the child process spawn another child process, thus having grandparents, grand-grandparents etc. or you can call the fork() on the parent side, having a single "father" and multiple children. This is a sample of code which implements the latter solution:

#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);
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文