孤兒進程組的定義:該進程組的每個成員的父進程要麼是該組的成員,要麼在其它會話中。
孤兒進程組的特點:
-
如果一個進程組包含一個或一個以上的停止的進程,當該進程組變成孤兒進程組時,該進程組中的每一個進程都會接收到一個 SIGHUP (掛掉)信號,然後緊接着會接收到 SIGCONT (繼續)信號。
但是對掛斷信號的系統默認動作是終止該進程。所以,如果要繼續執行子進程,就必須提供一個信號處理程序以捕捉該信號。 -
孤兒進程組是後臺進程組
-
孤兒進程組去讀控制終端時,read返回出錯並將errno設置爲EIO。
只有前臺作業能接收終端輸入,如果後臺作業試圖讀終端,那麼這並不是一個錯誤,但是終端驅動程序將檢測到這種情況,並且向後臺作業發送一個特定的信號SIGTTIN。該信號通常會暫時停止此後臺作業。由於孤兒進程組是後臺進程組,如果內核用SIGTTIN信號停止它,那麼進程組中的進程就再也不會繼續了。
至於書中說:父進程在終止時,子進程變成了後臺進程組,因爲父進程是由 shell 作爲前臺作業執行的。不懂什麼意思,有沒有老哥解釋一下,爲什麼會變成後臺進程組。
程序 9-12代碼:
#include "apue.h"
#include <errno.h>
static void sig_hup(int signo) {
printf("SIGHUP received, pid = %ld\n", (long) getpid());
}
static void pr_ids(char *name) {
printf("%s: pid = %ld, ppid = %ld, pgrp = %ld, tpgrp = %ld\n",
name, (long) getpid(), (long) getppid(), (long) getpgrp(), (long) tcgetpgrp(STDIN_FILENO));
fflush(stdout);
}
int main(void) {
char c;
pid_t pid;
pr_ids("parent");
if((pid = fork()) < 0)
err_sys("fork error");
else if(pid > 0)
sleep(5);
else {
pr_ids("child");
signal(SIGHUP, sig_hup);
kill(getpid(), SIGTSTP);
pr_ids("child");
if(read(STDIN_FILENO, &c, 1) != 1)
printf("read error %d on controlling TTY\n", errno);
}
exit(0);
}
終端運行如下:
hjm@hjm-Inspiron:~$ ./9-12
parent: pid = 2792, ppid = 2758, pgrp = 2792, tpgrp = 2792
child: pid = 2793, ppid = 2792, pgrp = 2792, tpgrp = 2792
SIGHUP received, pid = 2793
child: pid = 2793, ppid = 1, pgrp = 2792, tpgrp = 2758
read error 5 on controlling TTY
【析】:
由輸出可知,起初 child 屬於一個前臺進程組。當其父進程結束時,該子進程的進程組成爲了孤兒進程組,後臺進程組。
它試圖對讀標準輸入,正常情況下,將對該後臺進程組產生 SIGTTIN 信號,該信號會停止此後臺作業。!但是這是一個孤兒進程組,如果內核用SIGTTIN信號停止它,那麼進程組中的進程就再也不會繼續了。所以 POSIX.1 對這種情況下的處理是,read 返回出錯,並將 errno 設置爲 5.
至於孤兒進程組的輸出,這個取決於是否禁止後臺作業輸出到控制終端。