1.进程组
进程组是一个或多个进程的集合,有个唯一的进程组ID。每个进程组有一个组长进程,其进程ID等于进程组ID。进程组的生命期从创建开始,到最后一个进程离开为止。
获取和设置进程组ID的函数:
(1)返回调用进程的进程组ID:
pid_t getpgrp(void);
(2)返回进程pid的进程组ID:
pid_t getpgid(pid_t pid); //若pid = 0,与getpgrp函数等效
(3) 加入/创建一个进程组:
int setpgid(pid_t pid, pid_t pgid); //将pid进程的进程组ID设置为pgid;若pid = pgid,pid进程变为进程组组长;如果pid = 0,则使用调用者的进程ID;若pgid = 0,用pid进程的进程ID作为进程组ID。
一个进程只能为自身或其子进程设置进程组ID。在fork子进程后,如果要设置子进程的进程组ID,为避免出现竞争,父进程要设置子进程的进程组ID,子进程也要设置自身的进程组ID。
2. 会话
会话是一个或多个进程组的集合。
建立一个新会话:pid_t setsid(void);
如果调用setsid的进程不是一个进程组的组长,则创建一个新会话;若进程组组长调用该函数,则返回出错,为避免该情况,通常先调用fork,然后父进程终止,子进程继续,子进程继承父进程的进程组ID,而其进程ID是新分配的,如此则可以保证子进程不是一个进程组的组长。
一个进程创建一个新会话后:该进程变成新会话的会话首进程(此时该进程是新会话中的唯一进程);该进程成为一个新进程组的组长进程;该进程组没有控制终端。
返回会话首进程的进程组ID:
pid_t getsid(pid_t pid); //若pid=0,返回调用进程的会话受进程的进程组ID;pid不属于调用者所属的会话则无法获取。
3. 控制终端
一个会话可以有一个控制终端;与控制终端连接的会话首进程为控制进程;会话中的进程组可分为一个前台进程组和一个或多个后台进程组,前台进程组可以接收控制终端的输入和信号。控制终端的挂断信号会发送到控制进程。
4. 作业控制
一个作业是几个进程的集合,通常是一个进程管道;可以在前台或后台启动一个作业,命令行后加空格和&,则为后台作业(如:pr *.c | lpr &);前台进程组可以收到3个终端发送的信号:中断(Ctrl+C,SIGINT),退出(Ctrl+\,SIGQUIT),挂起(Ctrl+Z,SIGTSTP);
若后台作业试图读终端,终端驱动程序向后台作业发送SIGTTIN信号停止该后台作业,将后台作业转为前台就可以读终端;类似,若后台作业试图写终端,会产生SIGTTOU信号。
5. 孤儿进程组
定义:孤儿进程组的每个成员的父进程要么是该组的一个成员,要么不是该组所属会话的成员;
不是孤儿进程组的条件:该组中有一个进程,其父进程在属于同一会话的另一个组中(有机会重启该组中停止的进程)。
若进程组成为孤儿进程组,POSIX.1要求向孤儿进程组中处于停止状态的每个进程发送挂断信号(SIGHUP),接着又向其发送继续信号(SIGCONT)。