分类: LINUX
2012-01-20 21:00:05
++++++APUE读书笔记-09进程关系(08)++++++
10、孤儿进程组
================================================
我们曾经说过,一个进程如果它的父进程终止了,那么它就成为了孤儿进程,它将会被init收留。我们将会看到一个进程组也可以变成孤儿,并看看POSIX.1是如何处理这种情况的。
想想一个进程创建一个子进程,然后这个进程终止了。尽管这个情况是非常普遍的,但是,如果一个子进程被停止了(在作业控制中),同时父进程却终止了,这时候会发生什么事情呢?子进程如何被重新开始?子进程怎样知道它是否变成了孤儿进程?在参考资料给出的图中,描述了这种情况:父进程创建了一个子进程,子进程被stop了,然后父进程打算退出。
这个图在这里就不给出了,简单描述如下:login shell(2837)--(fork/exec)-->parent(6099)--(fork)-->child(6100)
其中parent和child在一个进程组中。相应的程序源代码在参考资料中也给出了。假设程序所运行的shell支持作业控制,前面已经说过,shell会把前台的进程放到前台进程自己的进程组中(6099),shell保持自己的进程组(2837)。子进程会继承父进程(6099)的进程组。在fork之后,
a.父进程父进程睡眠5秒,这样便于子进程在父进程终止之前执行。
b.子进程建立hang-up信号处理函数(SIGHUP),这样我们就可以看到是否有SIGHUP发送给子进程了(后面讨论信号处理函数)。
c.子进程使用kill给它自己发送stop(SIGTSTP)信号,这样会将子进程stop,效果和我们使用[Ctrl]z停止前台进程一样。
d.当父进程终止的时候,子进程变成孤儿,所以子进程的父进程ID变成了1,也就使init进程的id。
e.这时候,子进程变成了一个孤儿进程组的成员。在POSIX.1定义中指出,孤儿进程组就是这样的进程组:其中所有成员的父进程要么是该组的成员,要么是不在该组的同一个会话中。换句话说,进程组只要有一个成员进程其父进程是在同一会话的不同进程组,那么这个进程组就不是孤儿进程组。如果进程组不是孤儿进程组,那么就有机会通过它不同组同一会话的一个父进程来重新启动一个进程组中停止的非孤儿进程。
f.由于在父进程结束的时候进程组变成孤儿了,POSIX.1要求给新孤儿进程组中每一个stopped了的进程发送一个hang-up信号(SIGHUP),然后紧跟着一个conginue 信号(SIGCONT).
g.这样就会导致子进程在处理完hang-up信号之后继续执行了。默认来说hang-up信号会终止进程,所以我们这里提供了一个信号处理函数来处理相应的hang-up信号。
当变成孤儿进程之后,我们例子中的子进程由于hang-up而继续了,这时候,如果子进程立即尝试读取的话,根据前面的描述子进程会被停止(因为子进程这时是后台进程),但是又由于子进程组孤儿,所以没有办法恢复了,所以这种情况下,POSIX.1要求读取会返回错误,错误码errno为EIO。
参考: