3. 进程组和组长进程
(1)进程组
①一个或多个进程的集合;
②可以接受同一终端的各种信号,同一个信号发送进程组就等于发送给组中的所有进程。
③每个进程组有唯一的进程组ID
④进程组的消亡要等到组中所有的进程结束;
⑤kill发送信号组进程组:kill -9 -进程组号(注意进程组号前的“-”)
(2)组长进程
①每个进程组可以有个组长进程,组长进程的ID就是进程组的ID。
②组长进程可以创建进程组及该组中的进程。
③进程组的创建从第一个进程(组长进程)加入开始。
④进程组的组号取第一个加入组的进程(组长进程)的编号
(3)获取或设置进程组ID
头文件 |
#include <unistd.h> |
函数 |
pid_t getpgrp(void); //返回调用进程的进程组ID pid_t getpgid(pid_t pid); //进程pid所在进程组的ID,出错返回-1 int setpgid(pid_t pid, pid_t pgid); //将进程加入到指定的进程组中,其中pid为进程号,pgid为进程组号。成功返回0,出错返回-1。 |
功能 |
获取或设置进程组ID |
备注 |
①getpgid(0)与getpgid(getpid())等价,都是获得当前进程的进程组ID ②第1次调用setpgid,则创建一个进程组,而调用进程成为组长进程。如 setpgid(getpid(), getpid());//第2个参数为进程组ID,也是组长进程。 ③②用fork创建一个新进程后,子进程默认是和父进程在一个进程组内。 |
【编程实验】1.进程扇与分组
//process_swing_group.c
#include <unistd.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { pid_t pid; int i = 0; //创建进程组,组长进程为父进程 setpgid(getpid(), getpid()); pid_t group1 = getpgid(getpid()); //获取进程组ID pid_t group2; //构建进程扇 for(i = 0; i<3; i++) { pid = fork(); if(pid < 0 ){ perror("fork error"); exit(1); }else if(pid > 0) { //parent process //父进程中执行和子进程相同的操作,因为父、子进程 //谁先被调用未知,所以设置进程组ID时,需要父子进程同时设置 //以确保不管谁先运行,都能正确将他们分组 if(i == 0){ //将第一个子进程加入到group1中 setpgid(pid, group1); } if(i == 1){ //创建进程组,第二个子进程为组长进程 setpgid(pid, pid); group2 = getpgid(pid); } if(i == 2){ //第3个子进程加入到group2中 setpgid(pid, group2); } continue; //父进程继续运行,创建新的子进程 }else{ if(i == 0){ //将第一个子进程加入到group1中 setpgid(getpid(), group1); } if(i == 1){ //创建进程组,第二个子进程为组长进程 setpgid(getpid(), getpid()); group2 = getpgid(getpid()); } if(i == 2){ //第3个子进程加入到group2中 setpgid(getpid(), group2); } break; //要构建进扇,子进程须退出。 } } printf("pid = %d, ppid = %d, pgid = %d\n", getpid(), getppid(), getpgid(0)); for(i=0; i<3; i++) wait(0); } /*输出结果: pid = 3196, ppid = 2447, pgid = 3196 pid = 3198, ppid = 3196, pgid = 3198 pid = 3197, ppid = 3196, pgid = 3196 pid = 3199, ppid = 3196, pgid = 3198 */
【编程实验】2.进程链与分组
//process_link_group.c
#include <unistd.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { setpgid(getpid(), getpid()); pid_t group1 = getpgid(getpid()); pid_t pid; int i = 0; //构建进程链 for(i = 0; i<2; i++) { pid = fork(); if(pid < 0 ){ perror("fork error"); exit(1); }else if(pid > 0) { //parent process if(i == 0){ //创建进程组2,第1个子进程作为组长进程 setpgid(pid, pid); } if(i == 1){ //将第2个子进程加入到group1 setpgid(pid, group1); } break;//在进程链,父进程操作完退出循环 }else{ //child process if(i == 0){ //创建进程组2,第1个子进程作为组长进程 setpgid(getpid(), getpid()); } if(i == 1){ //将第2个子进程加入到group1 setpgid(getpid(), group1); } continue; //子进程继续创建新的子进程 } } printf("pid = %d, ppid = %d, pgid = %d\n", getpid(), getppid(), getpgid(0)); wait(0); } /* pid = 3216, ppid = 2447, pgid = 3216 pid = 3217, ppid = 3216, pgid = 3217 pid = 3218, ppid = 3217, pgid = 3216 */
【编程实验】3. 操作进程组
//process_group3.c
#include <unistd.h> #include <stdio.h> #include <stdlib.h> /*父子进程加入同一进程组*/ //说明: //(1)默认即使以下代码中不加入setpgid的操作,fork出来的子进程与父进程仍会默认地属一进程组 //(2)kill -9 -进程组ID,则父子进程均会收到退出进程的信号 //(3)如果先kill父进程,则子进程成为孤儿进程,会被1号进程领养 //(4)如果先kill子进程,则子进程成为僵尸进程。如果再kill父进程,则回收僵尸进程。 int main(void) { //创建进程组,父进程作为组长进程 pid_t pid = fork(); if(pid < 0){ perror("fork error"); exit(1); }else if(pid > 0){ //parent process //将子进程加入到父进程所在的组 setpgid(pid, getpgid(getpid())); }else{ //child process //将子进程加入到父进程所在的组 setpgid(getpid(), getpgid(getppid())); } printf("pid = %d, ppid = %d, pgid = %d\n", getpid(), getppid(), getpgid(0)); pause();//暂停。父子进程都会执行到这里。 return 0; } /*输出结果: pid = 3301, ppid = 2447, pgid = 3301 pid = 3302, ppid = 3301, pgid = 3301 */