每个进程都属于一个进程组。进程组通常是与同一个作业相关联的,可以接受来自同一个终端的各种信号。每个进程组都有
一个唯一的进程组ID。进程组ID类似于进程ID,可以存放在pid_t数据类型中。函数getpgrp返回调用进程的进程组ID。
#include <unistd.h> pid_t getpgrp(void); //返回值:调用进程的进程组ID。每个进程都可以有一个组长进程,组长进程的标识是:进程组ID等于其进程ID。
实践:
#include <stdio.h> #include <unistd.h> int main(){ printf("pgrp=%d,pid=%d\n",getpgrp(),getpid()); return 0; }运行结果:
pgrp=590,pid=590
可见该进程就是进程组长。
组长进程可以创建一个进程组,创建该组中的进程,然后终止,只要在某个进程中的有一个进程存在,则该进程组就存在,
这与其组长进程是否终止无关。进程组中的最后一个进程可以终止,或者转移到另一个进程组。
进程可以通过调用setpgid来加入一个现有的组或者创建一个新进程组。
#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。
一个进程智能为它自己或者它的子in成设置进程组ID,在它的子进程调用了exec函数之一后,它就不能再改变该子进程的进程
组ID。
在大多数作业控制shell中,在fork之后调用此函数,使父进程设置其子进程的进程组ID,并且使子进程设置其自己的进程组ID,
这2个调用中有一个是冗余的,但是让父子进程组都这么做可以保证子进程成为新的进程组的组长。
实践:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> int main(){ pid_t pid; if((pid=fork())<0){ perror("fork"); return -1; }else if(pid == 0){ setpgid(getpid(),getpid()); printf("child pgrpid=%d,pid=%d\n",getpgrp(),getpid()); exit(0); } setpgid(pid,pid); printf("parent pgrpid=%d,pid=%d\n",getpgrp(),getpid()); waitpid(pid,NULL,0); return 0; }运行结果:
parent pgrpid=1996,pid=1996
child pgrpid=1997,pid=1997