unix进程关系主要有三种:父进程和子进程、进程组、进程会话。
1、进程组
每个进程除了有一个进程ID之外,还属于一个进程组。进程组是一个或多个进程的集合。通常他们与同一作业相关联,可接受来自同一终端的各种信号。
函数getpgrp返回调用进程的进程组ID。
#include<unistd.h> pid_t getpgrp(void);
每个进程组都有一个组长进程,组长的标志是其进程ID等于进程组ID。组长进程可以创建一个进程组,然后就终止。只要进程组中有一个进程存在,那么进程组就存在,跟组长进程是否存在没有关系。进程组中的最后一个进程可以终止,或者转移到另一个进程组。
进程可以通过调用setpgid加入一个现有的组或者创建一个新的进程组。
int setpgid(pid_t pid,pid_t pgid);
2、会话
会话是一个或多个进程组的集合,下面一个会话中有三个进程组:
通常是由shell的管道将几个进程编成一组的。
进程调用setsid函数来建立一个新的会话:
pid_t setsid(void);
如果调用进程不是一个进程组长,那么这个函数创建一个新的会话。有三件事发生:
(1)该进程变成新会话的会话首进程。(会话首进程是创建该会话的进程。)该进程是这个新会话里的唯一进程。
(2)该进程变为一个新进程组的进程组长。新进程组ID就是该调用进程的进程ID。
(3)该进程没有控制终端。如果进程在调用setsid之前有一个控制终端,那么这个关联被中断。
PS:如果调用者已经是一个进程组长,那么这个函数返回一个错误。为了保证不出现这种情况,通常的做法是调用fork,然后使父进程终止,而让子进程继续。
3、控制终端
会话和进程组有几个其它的特性::
(1)会话可以有单一的控制终端。这通常是在登录到其上的终端设备(在终端登录的情况下)或者伪终端设备(在网络登录的情况下)。
(2)建立与控制终端连接的会话首进程被称为控制进程。
(3)一个会话里的几个进程组可以被分为一个前台进程组和一个或多个后台进程组。
(4)如果一个会话有一个控制终端,那么它有一个前台进程组,而在这个会话里的所有其它进程组都是后台进程组。
(5)每当我们输入终端的中断键(经常是DELETE或Control+C),就会将中断信号发送给前台进程组的所有进程。
(6)无论何时我们输入终端的退出键(常常是Ctrl+),就会将退出信号发送给前台进程组的所有进程。
(7)如终端接口检测到调制解调器或者网络连接断开连接,则将挂起信号发送给控制进程(会话首进程)。
通常,我们不必担心控制终端,登陆时,将自动建立控制终端。
4、作业控制
作业控制是一项由shell支持的特性,允许运行多项作业,一个在前台执行,其他在后台运行。
作业和进程的区别是它指整个命令行所需的全部进程。进程由内核控制,作业由shell控制。
作业控制允许在一个终端上启动多个作业(进程组),它控制哪一个作业可以访问该终端以及哪些作业在后台运行。作业控制要求三种形式的支持:
(1) 支持作业控制的shell。
(2) 内核中的终端驱动程序必须支持作业控制。
(3) 必须提供对某些作业控制信号的支持。
5.孤儿进程组
一个父进程已终止的进程称为孤儿进程(orphan process),这种进程由init进程收养。
定义1:一个进程组不是孤儿进程组的条件是,该组中每个成员的父进程要么是该组的一个成员,要么不是改组所属会话的成员。
定义2:不是孤儿进程组的条件是,该组中有一个进程,其父进程属于同一会话的另一个组中。