【问题标题】:How to fork multiple processes from a same parent?如何从同一个父进程分叉多个进程?
【发布时间】:2015-01-26 18:00:14
【问题描述】:

我正在尝试从同一个父级创建多个进程,但它总是以比预期更多的进程结束。我不知道该怎么做,在这里需要一些帮助。

我在网上找了一段代码,试了一下,

int main ()
{
    pid_t pid=0;
    int i=0;
    for (i=0; i<3; i++)
    {
        pid=fork();
        switch(pid)
        {
            case 0:
            {
                cout<<"\nI am a child and my pid is:"<<getpid();
                cout<<endl;
                exit(0);
                break;
            }
            default:
            {
                cout<<"\nI am a parent and my pid is: "<<getpid();
                cout<<"\nMy child pid is: "<<pid;
                cout<<endl;
                wait(NULL);
                break;
            }
        }
    }
  return 0;
 }

此代码确实有效,并从同一父级创建了 3 个子级。但是,这似乎是因为在创建每个子进程后,它立即被终止。所以它不会在下一轮 for 循环中分叉更多的孙子进程。但是我需要让这些子进程运行一段时间,并且他们需要与父母沟通。

【问题讨论】:

  • 它是否产生输出“我是个孩子......”?一旦您调用 exit,该过程就会结束。他们结束得如此之快的原因是你在这个过程中没有做任何事情。您应该调用一些 CPU 密集型函数,而不是打印并立即退出。
  • 这不是fork的问题,而是简单的逻辑问题。 fork() 在子节点中返回 0。在纸上追踪这里发生的事情,没有孩子的exit,循环再次运行,fork 再次执行。你想要做的是如果进程是孩子,你走出循环,否则你继续循环和分叉......
  • 感谢两位回答我的问题。我通过使用 if..else 而不是 case..switch 修改了我的代码,并在分叉子进程的末尾添加了一个 break 以退出循环,它可以工作!!!!!!我得到了我想要的!
  • 不要在儿童中打电话给exit。这会导致atexit 任务(例如刷新缓冲区)不止一次发生。使用_exit
  • 我不知道你到底在问什么。您的代码实现了标题中的目标。在正文的最后,你陈述你真正想做的事情。但是你不会问任何关于如何做到这一点的问题。所以你会得到愚蠢的回答,比如“编写你需要的代码,如果遇到麻烦,请寻求帮助”。

标签: linux c++ fork process


【解决方案1】:

子进程可能会立即中断循环以在外部继续其工作

int main ()
{
   cout<<"\nI am a parent and my pid is: "<<getpid()<<endl;

   pid_t pid;
   int i;
   for (i=0; i<3; i++)
   {
       pid=fork();
       if(pid == -1)
       {
           cout<<"Error in fork()"<<endl;
           return 1;
       }
       if(pid == 0)
           break;
       cout<<"My child "<<i<<" pid is: "<<pid<<endl;
    }

    if(pid == 0)
    {
        cout<<"I am a child  "<<i<<" and my pid is "<<getpid()<<endl;
        wait(NULL);  // EDIT: this line is wrong!
    }
    else
    {
        cout<<"I am a parent :)"<<endl;
        wait(NULL);  // EDIT: this line is wrong!
    }
    return 0;
}

编辑
wait(NULL) 行是错误的。如果进程没有活跃的子进程,wait() 没有任何作用,所以这里的子进程没用。 OTOH 在父进程wait() 中暂停执行,直到 任何 个子进程退出。我们在这里有三个孩子,所以必须wait() 三次。此外,我们无法提前知道孩子完成的顺序,因此我们需要更复杂的代码。像这样的:

struct WORK_DESCRIPTION {
    int    childpid;
    // any other data - what a child has to do
} work[3];

for(i=1; i<3; i++) {
    pid=fork();
    ...
    work[i].childpid = pid;
}

if(pid == 0)    // in a child
{
    do_something( work[i] );
}
else
{
    int childpid;
    while(childpid = wait(NULL), childpid != 0)
    {
        // a child terminated - find out which one it was

        for(i=0; i<3; i++)
            if(work[i].childpid == childpid)
            {
                // use the i-th child results here
            }
    }
    // wait returned 0 - no more children to wait for
}

【讨论】:

  • 我对这里的 pid 还是有些困惑。在上面的代码中,首先在 for 循环中 fork 所有 3 个孩子,然后使用 if(pid==0) 让每个孩子打印一个 msg。这很好,因为他们都做同样的事情。但是如果我想让每个孩子做不同的工作怎么办,在这种情况下我该如何选择一个孩子呢?我所做的是我fork一个孩子,如果pid == 0,做点什么;否则(返回父级),分叉第二个孩子,如果 pid ==0,做另一件事,依此类推。还有其他方法吗?
  • 每个子进程都继承其父数据的副本,以及其中的i 变量(这就是我在这里打印它的原因)。因此,您可以创建switch(i){...} 来为每个孩子选择合适的工作。注意:没有“返回父母”,我的意思是子进程没有“返回”。由于fork() 父母和孩子同时运行。如果您想与子进程同步(例如使用他们的结果),则需要在父进程中wait()
  • @Karen 编辑了我的答案。
  • 我在 en 编辑中描述的方式,一旦子进程可用,您就可以使用它们。您还可以使用 3 参数 wait() 使其更简单,只需按照孩子开始的顺序等待孩子,而不是在孩子完成时进行捕捉:for(i=0;i&lt;3;i++) {wait(work[i].childpid, ..., ...); ...}(或者可能有相应的 1 参数 waitpid() 函数 - 请参阅手册页)。
猜你喜欢
  • 2021-05-31
  • 2012-04-19
  • 1970-01-01
  • 1970-01-01
  • 2011-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-28
相关资源
最近更新 更多