【问题标题】:fork() within a fork()fork() 在 fork() 中
【发布时间】:2010-03-08 13:18:57
【问题描述】:

有什么方法可以区分程序中不同 fork() 函数创建的子进程。

global variable i;

SIGCHLD handler function()
{
  i--;
}

handle()
{
  fork() --> FORK2
}

main()
{
  while(1)
  {
     if(i<5)
     {
        i++;
        if( (fpid=fork())==0) --> FORK1
           handle()
        else (fpid>0)
           .....
     }
  }
}

有什么方法可以区分由 FORK1 和 FORK2 创建的子进程吗?因为我试图在 SIGCHLD 处理函数中减少全局变量 'i' 的值,并且它应该只为由 FORK1 创建的进程减少 ..

我尝试使用数组并保存由 FORK1 创建的子进程的进程 ID,这是由父进程完成的。只有当死子的进程 id 在数组中时,我才会递减 'i' 的值...

但是我遇到了以下场景的问题

child1、parent1、child1 被杀child2child2 被杀、parent2

在 child1 的情况下,因为它在 parent1 之后被杀死,所以数组正确更新。

但是如果 child2 在它的 pid 值被数组中的 parent2 更新之前就被杀死了呢?在 SIGCHLD 信号处理函数内部,因为 child2 PID 值不在数组中,所以“i”值没有相应递减..

那么有没有更好的办法解决这个问题??

【问题讨论】:

标签: c linux fork signals


【解决方案1】:

由于您已经在 SIGCHLD 处理程序中保存了要减少 i 值的 PID 列表,因此可能会让您感到困惑的部分是在更新列表。

您可以在使用sigprocmask() 执行信号处理程序期间屏蔽/阻止其他SIGCHLD 信号。这应该为您提供足够的时间来更新您的进程 ID 的数组/列表,而不必担心收到另一个 SIGCHLD。信号处理例程完成后,阻塞掩码必须返回到其原始值。

尝试将类似于以下内容的内容添加到您的 SIGCHLD 处理程序:

sigset_t mask;
sigset_t orig_mask;

sigemptyset (&mask);
sigaddset (&mask, SIGCHLD);

/* temporarily mask/block SIGCHLD signals and save original mask */
if (sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0) {
    perror ("sigprocmask - %s",  strerror(errno));
}

/* process SIGCHLD via waitpid() and update PID list as necessary */
...

/* restore original mask */ 
if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) {
    perror ("sigprocmask - %s", strerror(errno));
}

更新

重新检查您的问题后,我发现您有一个竞争条件,其中子进程在父进程可以将其 PID 添加到列表之前终止。

一种可能的解决方案仍然是在临界区使用sigprocmask() 来阻止SIGCHLD 信号。在这种情况下,您需要在调用fork() 之前阻止SIGCHLD 信号,并在将PID 添加到列表后在父代码中取消阻止它。如果孩子死了,信号处理程序将在您解除信号阻塞后被调用,这应该保证 PID 在列表中。

【讨论】:

  • 实际上我在处理 SIGCHLD 信号处理函数中的数组 List 时没有遇到任何问题......最初使用子进程的进程 ID 更新数组是由父进程完成的。因此,在执行顺序的情况下,类似于 .... child1, parent1, child2, child3, parent2, parent3 ... 如果 child2 在 parent2 代码执行之前被杀死,则 ARRAY 不会因此而更新 child2 PID SIGCHLD 信号处理程序不会减少 i 值,因为数组中不存在 pid
  • 现在我对你的问题有了更好的理解,我已经相应地更新了我的答案。
  • 你的意思是我应该在 fork() 之前阻止 SIGCHLD 信号,并在我进入父进程后解除阻止.. ??
  • 这不会造成竞争条件吗?最好使用 sigaction 设置信号处理程序。
【解决方案2】:

使用:

getppid() function . 

【讨论】:

  • 你的意思是我应该在 SIGCHILD 信号处理函数中使用 getppid() ... ??在那种情况下,它没有多大用处......??
【解决方案3】:

如果我理解得很好,您可能对waitpid() 系统调用感兴趣。 它允许您等待特定的孩子(给定一个 pid)。因此,如果您跟踪由 fork1 和 fork2 创建的 pid,那么只有在 fork1 的孩子死亡时,您才能减少 i 变量。

【讨论】:

  • 为了维护由 fork1 创建的所有子进程的列表,我在父进程中使用一个数组来更新具有子进程 ID 的数组,并且在 SIGCHLD 处理程序函数中我试图减少该值仅当它的 PID 在数组内时才为 i 。但是有一个问题 ..如果子进程死得太快以至于即使父进程中的代码也没有执行,那么数组没有得到正确的值更新..
猜你喜欢
  • 2015-07-16
  • 2018-06-16
  • 1970-01-01
  • 2016-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-29
  • 2023-03-24
相关资源
最近更新 更多