3.进程组
1).每个进程属于一个进程组,这个进程组从同样的终端获得信号
函数getpgrp返回调用进程的进程组ID,结果也用pid_t表示:
#include <unistd.h> pid_t getpgrp(void); //返回调用进程的进程组ID
2)SUS定义getpgid函数作为一个XSI扩展来效仿1)中函数的行为
#include <unistd.h> pid_t getpgid(pid_t pid); //成功返回进程组ID,错误返回-1
如果pid为0,返回调用进程的进程组ID。因而getpgid(0)等价于getpgrp();
3).每个进程组可以有一个进程组长。这个组长和它的进程组ID相等的进程ID于来标识(Leader的ProcessID = Process Group ID)。可能一个进程组长会创建一个进程组、创建这个组的进程,然后终止。只要至少有一个进程在这个组里,这个进程组便仍然存在,不管进程组长是否终止。一个进程加入一个存在的进程组或创建一个新的进程组,通过调用setpgid:
#include <unistd.h> int setpgid(pid_t pid, pid_t pgid); //成功返回0,错误返回-1
setpgid函数将pid进程的进程组ID设置为pgid。如果两个参数相等,则由pid指定的进程成为进程组长。如果pid为0,那么使用调用者的进程ID。同样,如果pgid为0,由pid指定的进程ID作为进程组ID被使用。
PS:一般使进程设置其子进程的进程组ID,并且使子进程设置其中经的进程组ID
4.会话
进程调用setsid函数来建立一个新的会话
#include <unistd.h> pid_t setsid(void); //返回进程组ID;错误返回-1
如果调用进程不是一个进程组长,那么这个函数创建一个新的会话。有三件事发生:
1).该进程变成新会话的会话首进程。(会话首进程是创建该会话的进程。)该进程是这个新会话里的唯一进程。
2).该进程变为一个新进程组的进程组长。新进程组ID就是该调用进程的进程ID。
3).该进程没有控制终端。如果进程在调用setsid之前有一个控制终端,那么这个关联被中断。
PS:如果调用者已经是一个进程组长,那么这个函数返回一个错误。为了保证不出现这种情况,通常的做法是调用fork,然后使父进程终止,而让子进程继续。
getsid函数返回一个进程的会话领导的进程组ID
#include <unistd.h> pid_t getsid(pid_t pid); //返回会话领导的进程组ID,错误返回-1
如果pid为0,getsid返回调用进程的会话领导的进程组ID。由于出于安全原因考虑,一些实现可能有如下限制:如果pid不属于调用者所在的会话,调用进程不能得到会话领导的进程组ID。
5.控制终端
会话和进程组有几个其它的特性::
1).会话可以有单一的控制终端。这通常是在登录到其上的终端设备(在终端登录的情况下)或者伪终端设备(在网络登录的情况下)。
2).建立与控制终端连接的会话首进程被称为控制进程。
3).一个会话里的几个进程组可以被分为一个前台进程组和一个或多个后台进程组。
4).如果一个会话有一个控制终端,那么它有一个前台进程组,而在这个会话里的所有其它进程组都是后台进程组。
5).每当我们输入终端的中断键(经常是DELETE或Control-C),就会将中断信号发送给前台进程组的所有进程。
6).无论何时我们输入终端的退出键(经是Control+),就会将退出信号发送给前台进程组的所有进程。
7).如终端接口检测到调制解调器或者网络连接断开连接,则将挂起信号发送给控制进程(会话首进程)。