二十七、Linux 进程与信号---进程组和组长进程

27.1 进程组

27.1.1 进程组介绍

  • 进程组为一个或多个进程的集合
  • 进程组可以接受同一终端的各种信号,同一个信号发送进程组等于发送给组中的所有进程
  • 每个进程组有唯一的进程组 ID
  • 进程组的消亡要等到组中所有的进程结束
  • 进程组的消亡:kill 发送信号给进程组
    • kill -9  -进程组号

27.1.2 进程组 ID 获取--- getpgrp 和 getpgid

(1)getpgrp --- 获取调用进程的进程组ID

 #include <unistd.h>
pid_t getpgrp(void);
  • 函数说明
    • getpgrp()用来取得目前进程所属的组识别码。此函数相当于调用 getpgid(0);
  • 返回值
    • 返回目前进程所属的组识别码。

(2)getpgid --- 获取 pid 所在进程组的 ID  

 #include <unistd.h>
pid_t getpgid( pid_t pid);
  • 函数说明
    • getpgid()用来取得参数 pid 指定进程所属的组识别码。如果参数 pid 为0,则会取得目前进程的组识别码。
  • 返回值
    • 执行成功则返回组识别码,如果有错误则返回 -1 ,错误原因存于 errno 中。
  • 错误代码
    • ESRCH 找不到符合参数 pid 指定的进程。
  • getpgid(getpid()) 获取指定进程的进程组
  • getpgid(0) 获取当前进程的进程组

27.2 组长进程

27.2.1 概念

  • 每个进程组可以有个组长进程,组长进程的ID就是进程组的ID
  • 组长进程可以创建进程组以及该组中的进程
  • 进程组的创建从第一个进程(组长进程)加入开始
  • 进程组的组号取第一个加入组的进程(组长进程)编号

27.2.2 设置进程组 ID--- setpgid(创建进程组或将指定进程加入到指定的进程组中)

 #include <unistd.h>
int setpgid(pid_t pid,pid_t pgid);
  • 函数说明
    • setpgid() 将参数 pid 指定进程所属的组 ID 设为参数 pgid 指定的组 ID。如果参数 pid 为 0 ,则会用来设置目前进程的组识别码,如果参数 pgid 为0,则会以目前进程的进程 ID 来取代。
  • 函数功能:将进程加入到指定的进程组中, pid 为进程号, pgid 为组号
  • 返回值
    • 执行成功则返回组 ID,如果有错误则返回-1,错误原因存于 errno 中。
  • 错误代码
    • EINVAL 参数 pgid 小于0。
    • EPERM 进程权限不足,无法完成调用。
    • ESRCH 找不到符合参数 pid 指定的进程。

27.3 例子

27.3.1 构建进程扇组

  构建一个进程扇,要求每两个进程为一个进程组,如下所示

  二十七、Linux 进程与信号---进程组和组长进程

  

 #include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h> int main(void)
{ //创建进程组,组长进程为父进程
setpgid(getpid(), getpid()); /* 组1 */
// 或 pid_t group1 = getpgid(0);
pid_t group1 = getpgid(getpid());
pid_t group2; int i = ;
pid_t pid; for(; i < ; i++) {
pid = fork();
if(pid < ) {
perror("fork error`");
exit();
} else if(pid > ) {//父进程
//父进程中执行和子进程相同的操作
if(i == ) {
//要注意fork 在父进程中返回的是子进程的 pid
setpgid(pid, group1);
} //第二个子进程作为组长进程,要创建进程组
if(i == ) {
setpgid(pid, pid);
group2 = getpgid(pid);
} if(i == ) {
//第三个子进程加入到 group2
setpgid(pid, group2);
}
} else {//子进程
//将第一个子进程加入到 group1
if(i == ) {
setpgid(getpid(), group1);
} //第二个子进程作为组长进程,要创建进程组
if(i == ){
setpgid(getpid(), getpid());
group2 = getpgid(getpid());
} if(i == ) {
setpgid(getpid(), group2);
} //因为是进程扇,每一个子进程要退出循环
//父进程继续循环 fork
break;
}
} printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid()); //防止僵尸进程产生
for(i = ; i < ; i++) {
wait();
} exit();
}

  编译运行:

  二十七、Linux 进程与信号---进程组和组长进程

27.3.2 构建进程链组

  二十七、Linux 进程与信号---进程组和组长进程

 #include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h> int main()
{
//创建进程组1,父进程为组长进程
setpgid(getpid(), getpid());
pid_t group1 = getpgid(getpid()); pid_t pid;
int i = ;
for(;i < ; i++) {
pid = fork();
if(pid < ) {
perror("fork error");
exit();
} else if(pid > ) {
if(i == ) {
//创建进程组2,第一个子进程作为组长进程
setpgid(pid, pid);
} if(i == ) {
//将第二个子进程加入到 group1中
setpgid(pid, group1);
} // 在进程链中,父进程操作完退出循环
break;
} else if(pid == ) { if(i == ) {
//创建进程组2,第一个子进程作为组长进程
setpgid(getpid(), getpid());
} if(i == ) {
//将第二个子进程加入到 group1中
setpgid(getpid(), group1);
}
}
} printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid()); //防止僵尸进程产生
for(i = ; i < ; i++) {
wait();
} return ;
}

  编译运行:

  二十七、Linux 进程与信号---进程组和组长进程

27.3.3 进程组删除

 #include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h> int main(void)
{
//创建进程组,父进程作为组长进程
setpgid(getpid(), getpid()); pid_t pid = fork();
if(pid < ){
perror("fork error");
exit();
} else if(pid > ) {
//将子进程加入到父进程所在的组
setpgid(pid, getpgid(getpid()));
} else {
//将子进程加入到父进程所在的组
setpgid(getpid(), getpgid(getppid()));
} printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid()); pause();//进程暂停,等待信号 return ;
}

  编译运行:

(1)杀掉进程组

  二十七、Linux 进程与信号---进程组和组长进程

  二十七、Linux 进程与信号---进程组和组长进程

(2)杀掉父进程

  二十七、Linux 进程与信号---进程组和组长进程

  二十七、Linux 进程与信号---进程组和组长进程

  杀掉父进程后,子进程依然存在,只不过变成了孤儿进程,并被2323进程所领养

(3)杀掉子进程

  二十七、Linux 进程与信号---进程组和组长进程

  二十七、Linux 进程与信号---进程组和组长进程

  子进程变为了僵尸进程,子进程被杀死,但是父进程并没有回收子进程。

  杀掉父进程:

  二十七、Linux 进程与信号---进程组和组长进程

  僵尸进程被回收

27.3.4 子进程不加入父进程组中

 #include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h> int main(void)
{
//创建进程组,父进程作为组长进程
setpgid(getpid(), getpid()); pid_t pid = fork();
if(pid < ){
perror("fork error");
exit();
} else if(pid > ) {
//将子进程加入到父进程所在的组
setpgid(pid, getpgid(getpid()));
} else {
//将子进程加入到父进程所在的组
//setpgid(getpid(), getpgid(getppid()));
} printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid()); pause();//进程暂停,等待信号 return ;
}

  编译运行:

  二十七、Linux 进程与信号---进程组和组长进程

  二十七、Linux 进程与信号---进程组和组长进程

  没有将子进程加入到组中,依然将子进程加入到父进程组了。

  注意:从 shell 上启动一个父进程,然后从父进程上创建若干个子进程,默认情况下都加入到父进程所在的组中,组号就是父进程的 PID,组长就为父进程。

上一篇:一键安装IIS的点点滴滴——For所有Microsoft的操作系统(下)


下一篇:数据导入Excel时,出现ole error 800AC472这个错误,怎么解决。