进程组
进程组
(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. 测试代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t pid;
if ((pid = fork()) < 0)
{
perror("fork");
exit(1);
}
else if (pid == 0)
{
printf("child PID = %d\n", getpid());
printf("child Group ID = %d\n", getpgid(0)); //返回组id
sleep(7);
printf("-------Group ID of child id change to %d\n", getpgid(0));
exit(0);
}
else if (pid > 0)
{
sleep(1);
setpgid(pid, pid); //让子进程自立门户,成为进程组组长,以它的pid为进程组 id
sleep(13);
printf("\n");
printf("parent PID = %d\n", getpid());
printf("parent's parent PID = %d\n", getppid());
printf(" parent Group ID = %d\n", getpgid(0));
sleep(5);
setpgid(getpid(), getppid()); //改变父进程组id为父进程的父进程
printf("\n-------Group ID of parent is change to %d\n", getpgid(0));
while (1);
}
return 0;
}
输出结果: