赞
踩
本篇文章我们开始学习Linux中的进程组,进程组这个概念可能很多小伙伴都没有接触过,那么这篇文章将会教大家什么是进程组。
在操作系统中,进程组(Process Group)是一组相关联的进程的集合。每个进程组都有一个唯一的进程组ID(PGID)。
进程组的主要目的是为了实现作业控制(Job Control),即对一组相关的进程进行协调和管理。有些操作系统使用进程组来组织与终端会话(Terminal Session)相关的进程,以实现对终端的控制和管理。
以下是进程组的几个重要特点:
1.进程组中的进程共享同一个进程组ID(PGID)。
2.进程组中的每个进程都有一个唯一的进程ID(PID)。
3.进程组中的进程可以通过进程组ID或进程ID来标识和引用。
4.进程组可以有一个领导进程(Group Leader),它是进程组中的一个成员,但其PID与PGID相同。
5.进程组可以具有一个控制终端(Controlling Terminal),用于与终端会话相关联。
6.进程组可以用来实现作业控制,例如启动、停止、恢复、终止一组相关的进程。
通过进程组,操作系统可以对一组相关的进程进行集中管理和控制。例如,在一个终端会话中,用户可以使用作业控制命令如fg(将一个后台作业移到前台运行)、bg(将一个前台作业移至后台运行)和kill(终止一个作业)来控制和管理进程组中的进程。
进程组是多进程编程和系统管理中的重要概念,对于实现进程间通信、作业控制和并发编程等都具有重要意义。
首先先介绍三个相关的函数:
当一个进程组中的进程需要访问或修改进程组的相关信息时,可以使用以下三个系统调用:getpgrp,getpgid和setpgid。我将逐个解释它们的作用和用法。
getpgrp():
getpgrp()是一个系统调用,用于获取调用进程所属的进程组ID(PGID),即获取当前进程的进程组ID。其原型为:
pid_t getpgrp(void);
声明中的pid_t是一个整数类型,表示进程组ID。调用getpgrp()会返回当前进程所属的进程组ID。
getpgid():
getpgid()是一个系统调用,用于获取指定进程的进程组ID。其原型为:
pid_t getpgid(pid_t pid);
参数pid是指定进程的进程ID。调用getpgid(pid)会返回进程ID为pid的进程所属的进程组ID。
setpgid():
setpgid()是一个系统调用,用于设置指定进程的进程组ID。其原型为:
int setpgid(pid_t pid, pid_t pgid);
参数pid是指定进程的进程ID,参数pgid是要设置的进程组ID。调用setpgid(pid, pgid)会将进程ID为pid的进程的进程组ID设置为pgid。
但需要注意的是,在使用setpgid()进行设置时,有以下几种情况:
如果将pgid设置为0,表示将指定进程的进程组ID设置为其本身的进程ID。
如果将pgid设置为与指定进程的进程ID相同,表示将指定进程设置为新的进程组领导者(Group Leader)。
如果指定的pid与pgid参数相同,表示将当前进程设置为新的进程组领导者。
这些函数在多进程编程和作业控制中非常有用。例如,可以使用getpgrp()来获取当前进程所属的进程组ID,getpgid()可以用于获取指定进程的进程组ID,而setpgid()则可以用于更改进程的进程组ID。这些函数能够帮助进程组协同工作和实现作业控制的功能。
示例代码:
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char** argv) { pid_t pid = fork(); if(pid == 0) { printf("child pid : %d gpid : %d\n", getpid(), getpgrp()); } else { printf("parent pid : %d gpid : %d\n", getpid(), getpgrp()); } return 0; }
通过运行结果可以发现子进程和父进程属于同一个进程组。
进程组的组长是由操作系统内核根据一定规则设置的,并且通常是创建进程组的第一个进程。该进程组的组长进程ID(PID)与进程组ID(PGID)相同。
进程组组长的主要作用是:
1.进程组管理:
组长负责管理组内的其他进程。它可以使用setpgid()系统调用来创建新的进程组,并将其他进程加入到自己的进程组中。
2.作业控制:
在Unix操作系统下,作业控制(Job Control)是一种管理和控制前台和后台进程运行的机制。进程组组长在作业控制中起着重要的角色,它可以向操作系统发出信号以控制整个进程组的状态,如暂停(SIGSTOP)、继续(SIGCONT)或终止(SIGTERM)等。
3.进程间通信:
进程组组长还可以作为进程间通信的机制之一。组长可以通过进程组ID将消息发送给同一进程组中的其他成员进程。
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char** argv) { pid_t pid = 0; int i = 0; for(i = 0; i < 5; i++) { if((pid = fork()) > 0) { printf("parent pid :%d gpid : %d \n", getpid(), getpgrp()); } else if(pid == 0) { printf("child pid :%d gpid : %d \n", getpid(), getpgrp()); sleep(50); break; } else { printf("fork err\n"); } } sleep(120); return 0; }
运行结果:
创建出的子进程和父进程属于同一个进程组,并且父进程作为进程组长。
使用下面命令可以一次性的将进程组中的进程都杀死。
进程组组长被终止后,其他的进程还是存在的,进程组组长只是用于创建新的进程。
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char** argv) { pid_t pid = 0; int i = 0; if((pid = fork()) > 0) { setpgid(pid, pid); printf("parent pid : %d pgid : %d\n", getpid(), getpgrp()); } else if(pid == 0) { setpgid(pid, pid); printf("child pid : %d pgid : %d\n", getpid(), getpgrp()); } return 0; }
运行结果:
这里可以看到子进程的进程组已经被修改了,并且成为了进程组长。
那么为什么需要调用两次setpgid函数呢,因为创建完子进程后,无法确认是子进程先运行还是父进程先运行,所以在这里调用两次setpgid函数确保生效。
本篇文章主要给大家讲解了进程组的概念和学习了如何修改进程组的依附性。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。