首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >避免fork()/SIGCHLD竞争条件

避免fork()/SIGCHLD竞争条件
EN

Stack Overflow用户
提问于 2008-12-04 11:36:07
回答 4查看 8.4K关注 0票数 14

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

代码语言:javascript
复制
  // 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%的修正。

那么,你怎么纠正这种种族状况呢?如果有一个良好的推荐模式,请让我知道!

谢谢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2008-12-04 12:20:24

最简单的解决方案是在fork()之前用sigprocmask()阻止SIGCHLD信号,并在处理pid之后在父代码中解除阻塞。

如果子节点死亡,则在解除阻塞信号后将调用SIGCHLD的信号处理程序。这是一个关键部分的概念--在您的例子中,关键部分在fork()之前开始,在children.add()之后结束。

票数 16
EN

Stack Overflow用户

发布于 2010-06-09 01:29:10

如果你不能使用关键片段,也许一个简单的计数器就能完成这个任务。+1当加法时,-1当移除时,不管先发生哪一个,当全部完成时,你最终可以得到零。

票数 0
EN

Stack Overflow用户

发布于 2008-12-04 11:46:49

除了现有的“儿童”之外,还增加了一个新的“早期死亡”数据结构。这将使孩子们的物品保持干净。

代码语言:javascript
复制
  // 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。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/340283

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档