进程组
每个进程除了有一个进程ID之外,还属于一个进程组。
进程组是一个或多个进程的集合。每个进程组有一个唯一的进程组ID,进程组ID类似于进程ID。
获取进程组ID
在早期的UNIX系统中使用以下函数查看进程组ID:
#include <unistd.h>
pid_t getpgid(pid_t pid); //若成功返回进程组ID,出错返回-1
到了现在一般用以下函数:
#include <unistd.h>
pid_t getpgrp(void); //若成功返回调用进程的进程组ID
如果getpgid
函数中的pid参数为0,其实也就等同于getpgrp
。
组长进程
国不可一日无君,群不可一日无群主
———— 沃兹基.硕德
每个进程组都可以有一个组长进程,其进程ID等于其进程组ID。
组长进程可以创建一个进程组,创建该组中的进程,然后终止。只要在某个进程组中有一个进程存在,则该进程组就存在,这与其组长进程是否终止无关。
设置进程组
进程可以通过以下函数来加入一个现有的组或者创建一个新进程组:
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid); //若成功则返回0,出错返回-1
setpgid
函数将pid进程的进程组设置为pgid。如果这两个参数相同,则pid指定的进程成为进程组组长。
另外,如果pid = 0
,则使用调用者的进程ID;如果pgid = 0
,则由pid指定的进程ID作为进程组ID,成为组长。
每个进程只能为自己或者其子进程设置进程组ID。但是!子进程调用exec函数之后,他就不能改变该子进程的进程组ID。
在大多数作业控制shell中,在fork之后调用此函数,使父进程设置其子进程的进程组ID,并且使子进程设置其自己的进程组ID。
这里有个问题:为什么要设置两次,不麻烦么?
还记得我们在进程一文中提到的。由于内核进程调度原因,父子进程调度顺序未知的问题么?
没错,只有这样才能够保证子进程被正确的设置了进程组。
孤儿进程组
在POSIX.1中定义了孤儿进程组。
该进程组的每个成员的父进程要么是该组的成员,要么在其他会话中
所以说,下图的进程组1就不是孤儿进程组
因为进程组1中父进程的父进程不属于进程组1且不在会话2中。
而进程组2就是父进程,因为它的每个进程的父进程要么在本组中,要么在其他会话中。
孤儿进程组的特性
如果一个进程组包含一个或一个以上的停止的进程,当该进程组成为孤儿进程组,每个进程都会收到SIGHUP
信号,紧接着又会收到SIGCONT
信号。
参考文献
[1]UNIX环境高级编程(第二版)