进程组(作业)
概述
进程组由一个或多个共享同一进程组标识符(PGID)的进程组成
进程组有一个 进程组首进程,即创建了该组的进程,它的 PID 和 PGID 相同
进程组的生命周期:
-
开始:首进程创建组的时刻
-
结束:最后一个成员退出进程组的时刻
进程组的特性:
-
在特定的进程组中父进程能够等待任意子进程
-
信号能够被发送给进程组中的所有成员
API
pid_t getpgrp(void);获取一个进程的进程组ID
int setpgid(pid_t pid, pid_t pgid);设置调用进程的进程组ID

在作业控制shell中使用setpgid
一个进程在其子进程已经执行exec()之后就无法修改该子进程的进程组ID的约束条件会影响到基于shell的作业控制程序设计,即需要满足下列条件
一个任务(即一个命令或一组以管道符连接的命令)中的所有进程必须被放置在一个进程组中。这一步允许shell使用killpg()(或使用负的pid 值来调用kill())来同时向进程组中的所有成员发送作业控制信号。一般来讲,这一步需要在发送任意作业控制信号前完成。
每个子进程在执行程序之前必须要被分配到进程组中,因为程序本身是不清楚如何操作进程组ID的。
pid_t child_pid;
pid_t pipeline_pgid;
child_pid = fork();
if (child_pid == 0) {
setpgid(0, pipeline_pgid);
/* carry on exec() */
}
setpgid(child_pid, pipeline_pgid);
...
在处理由管道符连接起来的命令时事情会变得更加复杂一点,父shell需要记录管道中第一个进程的进程 ID 并使用这个值作为该组中所有进程的进程组 ID(pipelinePgid)
会话
概述
会话是一组进程组的集合,进程具有会话标识符(SID)
会话首进程 是创建该新会话的进程,它的 PID 和 SID 相同
任一时刻,会话中的其中一个进程组会成为终端 前台进程组,能够读取终端输入,其他进程组会成为 后台进程组
当到控制终端的连接建立起来(即打开)之后,会话首进程会成为该终端的控制进程。成
为控制进程的主要标志是当断开与终端之间的连接时内核会向该进程发送一个SIGHUP信号
API
pid_t getsid(pid_t pid);获取指定进程的会话ID
pid_t setsid(void);如果调用进程不是进程组首进程的话,创建一个新会话;如果调用进程是一个进程组首进程,那么setsid()调用会报出 EPERM 错误
一个进程组中的所有成员必须属于同一个会话(严格遵守会话和进程组之间的两级层次)
控制终端和控制进程
一个会话中的所有进程可能会拥有一个控制终端
会话刚被创建时,是 没有 控制终端的,只有当会话首进程打开一个 还没有成为某个会话的控制终端的终端时 才会建立控制终端
setsid(); // 创建新会话
open("/dev/tty", O_RDWR); // 如果一个进程拥有一个控制终端,那么打开特殊文件/dev/tty 就能够获取该终端的文件描述符,否则会失败
除非在调用open()时指定O_NOCTTY标记。一个终端至多只能成为一个会话的控制终端
控制终端会被由fork()创建的子进程继承并且在exec()调用中得到保持。
当会话首进程打开了一个控制终端之后它同时也成为了该终端的控制进程。在发生终端断开之后,内核会向控制进程发送一个SIGHUP信号来通知这一事件的发生。

前台和后台进程组
任一时刻,只有一个进程能够成为会话的 前台进程,其他所有进程都是 后台进程组
前台进程组 是唯一能够 自由读取和写入控制终端 的进程组,当信号产生时,终端驱动器会将信号发送给 前台进程组中的所有成员
pid_t tcgetpgrp(int fd); 返回指定终端的前台进程组的ID
int tcsetpgrp(int fd, pid_t pgid); 修改一个终端的前台进程组
作业控制

终端的前台作业的概念还用于仲裁终端I/O请求。只有前台作业中的进程才能从控制终端中读取数据。
系统通过SIGTTIN信号的分送来防止后台作业读取数据,这个信号的默认动作是停止作业。
如果设置了终端的TOSTOP 标记,那么系统会通过SIGTTOU信号的发送来防止后台任务向控制终端写入数据,这个信号的默认动作是停止作业。
当发生终端断开时,内核会向控制进程发送一个SIGHUP 信号通知它这件事情。这样的事件可能会导致一个链式反应,即向很多其他进程发送一个SIGHUP 信号。
首先,如果控制进程是一个shell(通常是这种情况),那么在终止之前,进程会向所有由其创建的进程组发送一个SIGHUP 信号。
第二,如果SIGHUP信号的分送导致了控制进程的终止,那么内核还会向该控制终端的前台进程组中的所有成员发送一个SIGHUP信号。
总结
进程组和会话在进程之间形成了一种两级层次关系:进程组是一组相关进程的集合,会话是一组相关进程组的集合。

posted on
浙公网安备 33010602011771号