【问题标题】:Multiple child creation with fork() in Linux在 Linux 中使用 fork() 创建多个子节点
【发布时间】:2012-03-30 13:06:14
【问题描述】:

我想使用fork() 创建多个孩子,但我遇到了问题。 喜欢:

///////////////////////// these are some class objects creation and calling
//  There are some functions calling from another class. about 5 functions I invoked.
// and some variables like.

    pid_t PID;
    int status = 0;
    char *x = new char[10];

///////////////////////// This for loop give me multiple children
// now one parent have multiple children in this case 10


    for( int i=0; i<10; i++ )
    {
        mNo++;
        rNo++;
        PID = fork();

        if( PID == FORK_ERROR )         // fork ERROR!
        {
            fprintf(stderr, "ERROR! In fork() [FORCE EXITING]... %d\n", errno);
            exit(EXIT_FAILURE);
        }
        else if( PID == CHILD )         // Do Child Stuff Here...
        {
            exit(status);
        }
        else            // Do parent Stuff Here...
        {

        }
    }
    PID = wait(&status);

////////////////////////////////////////////

这是我实现的代码,但存在一些问题。

我想问,当我在内存中创建一个孩子时,它会创建重复的内存。还有我声明的对象;他们是通过调用fork() 重新调用的吗?这是否意味着对于每个孩子来说,内存中都有在课堂上重新调用的对象?

如果我分叉,我希望之前的函数调用和变量对于每个子函数都应该是相同的,但不是非幂等函数。我希望你能明白。我知道这是一个非常简单的问题,但我正在处理的项目非常关键,它必须使用fork() 来实现,而不是在管道或线程中。

此外,我在重复我的问题,如果我 fork(),对象和变量会发生什么。在调用 fork 之前,它们只是重新分配还是再次为每个孩子重新调用?但我看到的是,它们会为每个孩子重新调用,这是我不想要的。那我该怎么办?

【问题讨论】:

  • 您是用 C 还是 C++ 编写代码?任选其一。
  • 真的很难理解你想要什么或者你的问题是什么。我猜你不希望你的所有对象都被fork()写时复制行为所复制。如果是这样,fork() 将无济于事。如果你想共享对象,你必须使用线程而不是进程。
  • “重新调用”是什么意思?
  • 好的。这不是一个难题。但你正在集中注意力。非常感谢你。所以,在我的代码中有对象创建和函数调用。函数调用意味着我正在尝试一些系统资源,比如一些文件。现在,如果正在分配相同的内存。那么为什么它会打印多个 cout。我在 fork 之前写的。以及为什么它一次又一次地访问我的文件。在每个孩子的创作上。我希望你能好好理解。告诉我哪里错了。请帮助我。

标签: c++ c linux operating-system fork


【解决方案1】:

fork() 的行为不会因你的意愿而改变。

当进程分叉时,同一程序有两个几乎相同的副本。差异在 POSIX 手册页(上面的链接)中列出。记忆是一样的。例如,C++ 中的对象不会被重新构造。例如,在每个进程中,所有的单例仍然是单例。

你能举个例子吗?

这是我在 1991 年写的完整主程序。我只更新了它以使用 main() 的原型,并且我已经包含了 Pipe 的 typedef 和 id 的定义:

static char id[] = "\n\n\nSQLMONITOR version 3.5 \n";
typedef int Pipe[2];

int main(int argc, char **argv)
{
    int     pid;
    Pipe    to_sqlexec;
    Pipe    from_sqlexec;

    setarg0(argv[0]);
    write(STDERR, id, sizeof(id)-1);
    if (pipe(to_sqlexec) < 0 || pipe(from_sqlexec) < 0)
        error("unable to create pipes");
    else if ((pid = fork()) < 0)
        error("unable to fork");
    else if (pid == 0)
        be_childish(argv, to_sqlexec, from_sqlexec);
    else
        be_parental(to_sqlexec, from_sqlexec);
    return(0);
}

be_childish() 函数继续进行一些管道操作(在执行另一个程序之前复制和关闭管道的适当部分。be_parental() 进程继续从其标准输入读取消息,将它们记录到文件中,并在to_sqlexec 管道的写入端将消息写入其子级的标准输入;然后它将在from_sqlexec 管道的读取端从子级读取响应,并记录该消息,然后将其写入其标准输出。因此,它将位于两个进程的中间,记录从一个进程到另一个进程的所有内容。进程之间的通信协议是同步的,这大大简化了生活。另一方面,当来自一个进程的数据完成时,计算起来相当困难。代码早于select()poll() 的广泛使用;现在,它不需要对消息进行太多分析。

但要注意的关键是fork() 之后的两个进程中的两个管道是相同的;实际上,唯一不同的变量是pid,它捕获来自fork() 的返回值。其他一切都与fork() 之前完全相同。

【讨论】:

  • 确切的例子是什么?在子进程中,就像在父进程中一样,所有已创建的变量仍将存在......嗯,线程应用程序变得更加复杂,因为子进程只有一个线程,而父进程可能有很多线程,但是线程这里不是问题。所以,子进程从fork()返回,接收值0作为返回值;父级从fork() 返回,接收其子级的PID。接下来会发生什么取决于代码。在你的情况下,你的孩子似乎用exit() 抹杀了自己,而父母继续繁殖更多。
  • OK.. 就我而言,还有一件事情正在发生。我只是在 for 循环之前 cout 并在 shell 上打印多次。它不应该打印多次,只需要打印父级,它应该只打印一次。不是吗。。那感觉我不好。这是为什么。
  • 啊...缓冲的 I/O 和未刷新的 I/O...总是很有趣。在 C 语言中,建议您在使用 fork() 之前使用 fflush(0) 刷新所有待处理的 I/O。对于 C++,您可能应该使用 cout &lt;&lt; endl; 或类似的东西(我对 C++ I/O 库的了解并不像它应该/应该的那样全面)。如果在 fork 之前不刷新,则 child 和 parent 都有等待写入的输出,因此 child 和 parent 最终都会写入相同的信息。孩子是父母的精确副本!
【解决方案2】:

当您分叉时,您的子进程是父进程的副本,包括堆。因此,您有一个单独的对象副本或使用 new 分配的内存。我不确定重新调用是什么意思,但是如果您在父级中使用 new() 分配了一个对象,那么您将在 2 个单独的进程中的 2 个单独的堆上拥有 2 个单独的对象。 一个是父进程中的原始副本,另一个是子进程中复制堆上的副本。

这将有助于更好地理解:Linux fork within class on heap

【讨论】:

  • 谢谢。为你解答。通过阅读互联网上的所有内容并进行搜索。我已经知道,在 fork 之前我已经创建了什么程序状态。在 fork 之后,它们将被复制。正如它应该。然后我想分别对复制的数据做什么。并平行。谢谢
【解决方案3】:

好像你不知道 fork() 是做什么的。这让您确信它是正确的功能似乎很奇怪。

阅读:

http://linux.die.net/man/2/fork

http://en.wikipedia.org/wiki/Fork_(operating_system)

乍一看,子进程似乎获得了父进程内存的副本。

【讨论】:

  • 谢谢,我知道这段代码正在做它应该做的事情。我想知道一个问题,对象和数据会发生什么。我在 fork 之前声明的。它需要一些线程工作。使用叉子。好的。我想解释什么:
  • obj 1;对象 2,对象 3,对象 1(); obj2(); obj3();
  • 现在我 fork()。并做所有的 fork 实现。他们是否会为每个孩子回忆这些物体发生了什么。我希望他们不要再去上课了。
  • 您将获得存储这些对象的内存的副本。它们没有被重新分配,或者任何东西,只是内存的副本。也就是说,您的孩子将拥有相同的对象,但它们会使用不同的内存。
  • 所以你能告诉我创建多个 child 的确切方法吗?我希望一个父母应该有多个孩子。以及我调用函数的对象。并且所有孩子都有相同的副本并使用它们。你能告诉我吗?
【解决方案4】:

如果你 fork,我认为,所有的对象和变量都将与父进程完全相同。我不明白“但是我看到他们为每个孩子重新调用”这里重新调用了什么?

【讨论】:

  • reinvoked 表示我如何通过函数来​​使用资源或对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-20
  • 2012-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多