2014-02-25 66 views
1

请在C考虑下面的代码:确实linux永远不会结束子进程,直到父节点结束?

int main() 
    { 
    pid_t cpid; 
    cpid = fork(); 
    if (cpid == -1) 
    { 
      perror("fork"); 
      return 0; 
    } 
    if (cpid == 0) 
    { 
      printf("I'm child\n"); 
      _exit(0); 
    } 
    else 
    { 
      while(1) 
      { 
        printf("I'm parent\n"); 
        sleep(1); 
      } 
    } 
    return 0; 
    } 

运行代码后,我希望它运行的孩子,离开它一旦完成。 但是当我运行

pgrep executable_name 

ps fax 

它显示的子进程ID,如果它只是工作过程的历史垃圾或它确实没有结束/终止我不知道孩子的过程?

在此先感谢

回答

5

孩子将一直等到父母死亡或父母用wait系统调用清除它。 (在孩子终止和清理之间的时间内,它被称为僵尸进程。)

原因是父级可能对子级的返回值或最终输出感兴趣,所以进程入口保持激活状态直到查询信息。

编辑:

使用SIGCHLD处理程序,立即清理,当他们死的过程不会阻塞示例代码:

http://arsdnet.net/child.c

要留意的是,系统调用(如睡眠,选择,或文件读/写)可以被信号中断。这是你在unix中应该处理的正常事情 - 它们失败并将errno设置为EINTR。发生这种情况时,您可以再次尝试完成操作。这就是为什么我的示例代码在父代中调用了两次睡眠 - 第一次长睡会被孩子死亡打断,然后第二次较短的睡眠让我们确认在父母死亡之前实际清理了进程。

顺便说一句,信号处理程序通常不应该做太多,他们应该尽快返回,并避免不是线程安全的东西;通常不鼓励在其中印刷。我在这里做过,所以你可以看到发生的一切。

+2

为了清楚起见:* only *当进程处于“僵尸”状态时进程表条目存活;所有其他资源都被释放。 – zwol

+0

好吧,这是一个解决方案,并感谢您给出的原因,但不等待父母,直到孩子的状态改变?我想要叉的并行化在第一个地方 – madz

+1

是的,等待块。你也可以设置一个SIGCHLD处理程序,并且只有等到它被触发时才能确保它不会被阻塞。信号在小孩终止时发送。您也可以忽略它,孩子在父母结束时会自动清理。 –

2

你需要调用wait()父,否则子进程将永远不会被收割(变成僵尸)。 *


*除非家长本身也退出。

+0

'_exit'和'_Exit'怎么样?它不应该是后者吗? – Brian

+1

@GIJoe在符合C11和POSIX的任何系统上,'_exit'和'_Exit'完全相同。 C11委员会担心(愚蠢地,IMNSHO)采用POSIX名称来实现具有不同(但实际上相同)文本规范的功能。这些差异仅仅是因为C11以不同于POSIX的方式描述事物,并不是因为意图不同。 – zwol

+0

如果您对子进程的状态不感兴趣,请忽略SIGCHLD信号,子进程将自动获得。 – nos