会话是一个或多个进程组的集合。
作业控制
yjp@yjp-VirtualBox:~$ cat > temp.foo & 在后台启动,但从标准输入读,收到SIGTTIN信号
[1] 2478
yjp@yjp-VirtualBox:~$ 键入回车
[1]+ Stopped cat > temp.foo 停止后台作业
yjp@yjp-VirtualBox:~$ fg %1 使1号作业成为前台作业
cat > temp.foo shell告诉我们哪个作业在前台
hello world 键入一行
yjp@yjp-VirtualBox:~$ cat temp.foo 检查该行送入文件
hello world
yjp@yjp-VirtualBox:~$
yjp@yjp-VirtualBox:~$ ps -o pid,ppid,pgrp,session,tpgid,comm
PID PPID PGRP SESS TPGID COMMAND
2435 2429 2435 2435 2913 bash
2913 2435 2913 2435 2913 ps ps是组长进程,此进程组是前台进程组
yjp@yjp-VirtualBox:~$ ps -o pid,ppid,pgrp,session,tpgid,comm &
[1] 2918
yjp@yjp-VirtualBox:~$ PID PPID PGRP SESS TPGID COMMAND 成为后台进程组
2435 2429 2435 2435 2435 bash
2918 2435 2918 2435 2435 ps
创建一个孤儿进程组
#include "apue.h"
#include <errno.h>
static void sig_hup(int signo)
{
printf("SIGHUP received, pid = %d\n", getpid());
}
static void pr_ids(char *name)
{
printf("%s: pid = %d, ppid = %d, pgrp = %d, tpgrp = %d\n",
name, getpid(), getppid(), getpgrp(), 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) /* parent */
{
sleep(5); /* sleep to let child stop itself */
exit(0); /* then parent exits */
}
else /* child */
{
pr_ids("child");
signal(SIGHUP, sig_hup); /* establish signal handler */
/*
若父进程退出导致进程组成为孤儿进程组,且该进程组中有进程处于停止状态(收到SIGSTOP或SIGTSTP信号),
SIGHUP信号会被发送到该进程组中的每一个进程。
*/
kill(getpid(), SIGTSTP); /* stop ourself */
pr_ids("child");
if(read(STDIN_FILENO, &c, 1) != 1) /* prints only if we're continued */
{
printf("read error from controlling TTY, errno = %d\n", errno);
exit(0);
}
}
return 0;
}
子进程的父进程ID没有变成1,而是1327 ?
子进程调用pr_ids后,程序试图读标准输入。后台进程组试图读控制终端时,则对该后台进程组产生SIGTTIN。但此时已是孤儿进程组,
如果内核用此信号停止它,则此进程组中的进程就再也不会继续。这时read返回出错,并将errno设置为EIO,即5.
父进程终止时,子进程被植入后台进程组,因为父进程时由shell作为前台作业执行的。