1.进程组
每个进程除了有一进程ID之外,还属于一个进程组。进程组中的各个进程接受来自同一终端的各种信号。每个进程组有唯一的进程组ID。
#include <unistd.h>
pid_t getpgrp(void)//得到调用进程的进程组ID
每个进程组都有一个组长。组长进程的进程组ID等于其进程ID。
进程可以调用setpgid加入一个现有的进程组或者创建一个新的进程组。
#include <unistd.h>
int setpgid(pid_t pid,pid_t pgid);
setpgid函数将pid进程的进程组ID设置为pgid。如果这两个参数相等,则由pid指定的进程变成进程组的组长。如果pid为0,则由pid指定的进程ID用作进程组的ID。
特别要注意的是,一个进程只能为它自己或它的子进程设置进程组ID。在它的子进程调用exec后,它就不能再更改它子进程的ID了。
2.会话
会话是一个或多个进程组的集合。如下所示:
进程可以通过setsid建立一个新会话。
#include <unistd.h>
pid_t setsid(void)
如果调用者不是一个进程的组长,则此函数会新创建一个会话。具体会发生下列三件事:
(1)该进程会变成新会话的会话首进程。
(2)该进程变成一个新进程组的组长。
(3)该进程没有终端控制。如果在函数调用之前该进程有一个终端,那么这种联系也被切断。
如果该进程是一个进程组的组长,则此函数返回出错。
#include <unistd.h>
pid_t getsid(pid_t pid);//
如果pid是0,则函数会返回调用进程的会话首进程组ID
3.控制终端的相关概念
(1)一个会话可以有一个控制终端。这通常是终端设备或者是伪终端设备。
(2)建立与控制终端连接的会话首进程被称为控制进程。
(3)一个会话中的几个进程可被分成一个前台进程组以及一个或多个后台进程组。
4.函数tcgetpgrp,tcsetpgrp,tcgetsid
需要有一种方法来通知内核哪一个进程组是前台进程组。
#include <unistd.h>
pid_t tcgetpgrp(int fd)
int tcsetpgrp(int fd,pid_t pgrpid)
函数tcgetpgrp返回前台进程组ID,它与在fd上打开的终端相关联。
如果进程有一个控制终端,则该进程可以调用tcsetpgrp将前台进程组ID设置为pgrpid。pgrpid应该为同一会话中的一个进程组的ID。fd必须引用该会话的控制终端。
#include<termios.h>
pid_t tcgetsid(int fd);//给出TTY文件描述符,通过这个函数就能获得首进程的进程ID
5.FreeBSD的实现
下图描绘了FreeBSD对于进程,进程组,会话,控制终端的实现: