请考虑以下fork() / SIGCHLD伪代码。

  // main program excerpt
    for (;;) {
      if ( is_time_to_make_babies ) {

        pid = fork();
        if (pid == -1) {
          /* fail */
        } else if (pid == 0) {
          /* child stuff */
          print "child started"
          exit
        } else {
          /* parent stuff */
          print "parent forked new child ", pid
          children.add(pid);
        }

      }
    }

  // SIGCHLD handler
  sigchld_handler(signo) {
    while ( (pid = wait(status, WNOHANG)) > 0 ) {
      print "parent caught SIGCHLD from ", pid
      children.remove(pid);
    }
  }

在上面的例子中有一个竞争条件。这是可能的“/* child stuff */”之前“/* parent stuff */”开始,这会导致孩子的PID被添加到孩子的列表它退出之后,从来没有被删除完成。在时机成熟时为应用程序关闭,家长会无休止地等待了已经完成的孩子完成。

的一个解决方案,我能想到的对抗这是具有两个列表:started_childrenfinished_children。我要补充在我加入到started_children现在同一个地方children。但在信号处理程序,而不是从children删除我的添加应用于finished_children。当应用程序关闭了下来,家长可以简单地等待,直到started_childrenfinished_children之间的差是零。

另一种可能的解决方案,我能想到的是使用共享存储器,例如分享孩子的父母的列表,并让孩子.add.remove自己?但我不知道太多关于这一点。

编辑:另一种可能的解决方案,这是浮现在脑海的第一件事,就是简单地在sleep(1)开始添加/* child stuff */但有趣的气味对我来说,这就是为什么我离开它。我也甚至不知道这是一个100%的修正。

那么,你将如何纠正这种竞争条件?如果有一个行之有效的模式推荐此,请让我知道!

感谢。

有帮助吗?

解决方案

简单的解决办法是用fork() sigprocmask()之前阻止SIGCHLD信号和在父代码解锁已处理的PID之后。

如果孩子死了,对于SIGCHLD信号处理程序将被解除你的信号后调用。这是一个关键部分的概念 - 。在你的情况临界段fork()之前开始和children.add()之后结束

其他提示

如果您无法使用关键的片段,也许一个简单的计数器可以做这个工作。 +1时添加,-1时捞出,没有母校哪一个先发生,你最终可以得到零时,一切都过去了。

在除了现有的“孩子”添加新的数据结构“早期死亡”。这将让孩子们的内容干净。

  // main program excerpt
    for (;;) {
      if ( is_time_to_make_babies ) {

        pid = fork();
        if (pid == -1) {
          /* fail */
        } else if (pid == 0) {
          /* child stuff */
          print "child started"
          exit
        } else {
          /* parent stuff */
          print "parent forked new child ", pid
          if (!earlyDeaths.contains(pid)) {
              children.add(pid);
          } else {
              earlyDeaths.remove(pid);
          }
        }

      }
    }

  // SIGCHLD handler
  sigchld_handler(signo) {
    while ( (pid = wait(status, WNOHANG)) > 0 ) {
      print "parent caught SIGCHLD from ", pid
      if (children.contains(pid)) {
          children.remove(pid);
      } else {
          earlyDeaths.add(pid);
      }
    }
  }

编辑:这可以,如果你的过程是单线程被简化 - earlyDeaths不必是一个容器,它只是为保持一个PID

也许乐观算法?尝试children.remove(PID),和如果失败,移动与寿命。

或者检查pid是在孩子试图将其删除?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top