进程组
(1)进程组,也称之为作业,BSD与1980年前后向UNIX中增加的一个新特性,代表一个或多个进程的集合。每个进程都属于一个进程组,在waitpid函数和kill函数的参数中都曾经使用到,操作系统设计的进程组的概念,是为了简化对多个进程的管理。
当父进程创建子进程的时候,默认子进程与父进程属于同一个进程组,进程组ID等于进程组第一个进程ID(组长进程)。所以,组长进程标识:其进程组ID等于其进程ID.
组长进程可以创建一个进程组,创建该进程组的进程,然后终止,只要进程组中有一个进程存在,进程组就存在,与组长进程是否终止无关。
(2)kill发送给进程组
使用 kill -n -pgid 可以将信号 n 发送到进程组 pgid 中的所有进程。例如命令 kill -9 -4115 表示杀死进程组 4115 中的所有进程。
进程组操作函数
1. getgrp函数:获取当前进程的进程组
pid_t getpgrp(void);
2. getpgid函数:获取进程的进程组ID
pid_t getpgid(pid_t pid);
分析:
- 如果pid = 0,那么该函数作用和getpgrp一样
3. setpgid函数作用:改变进程默认所属的进程组,通常可用来加入一个现有的进程组或新进程组。
int setpgid(pid_t pid, pid_t pgid);
分析:将参数1对应的进程,加入参数2对应的进程组中。
注意:
- 如改变子进程为新进程组,用fork后,exec前。
- 权级问题:非root进程只能改变自己创建的子进程,或有权限操作的进程。
ps ajx命令查看系统中的进程,参数a表示不仅列出当前用户的进程,也列出所有其他用户的进程,参数x表示不仅列有控制终端的进程,也列出所有无控制终端的进程,参数j列出与作业控制相关的信息。
注意:组长进程不能成为新会话首进程,新会话首进程必定会成为组长进程。
1. 测试代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 5 int main() 6 { 7 pid_t pid; 8 if ((pid = fork()) < 0) 9 { 10 perror("fork"); 11 exit(1); 12 } 13 else if (pid == 0) 14 { 15 printf("child PID = %d ", getpid()); 16 printf("child Group ID = %d ", getpgid(0)); //返回组id 17 sleep(7); 18 printf("-------Group ID of child id change to %d ", getpgid(0)); 19 exit(0); 20 } 21 else if (pid > 0) 22 { 23 sleep(1); 24 setpgid(pid, pid); //让子进程自立门户,成为进程组组长,以它的pid为进程组 id 25 26 sleep(13); 27 printf(" "); 28 printf("parent PID = %d ", getpid()); 29 printf("parent's parent PID = %d ", getppid()); 30 printf(" parent Group ID = %d ", getpgid(0)); 31 32 sleep(5); 33 setpgid(getpid(), getppid()); //改变父进程组id为父进程的父进程 34 printf(" -------Group ID of parent is change to %d ", getpgid(0)); 35 36 while (1); 37 } 38 return 0; 39 }
输出结果: