进程组
之前我们在查看系统进程相关信息时,会看到每一个进程的ID和其父进程的ID等相关信息,其中就有一个PGID,代表的是组ID。什么是组ID呢?进程除了有自己的一个进程ID之外,每一个进程还属于一个进程组。而这其中的PGID就是组ID,指明了该进程是属于哪一个进程组。
那么什么是进程组呢?其实这个进程组就是一个或多个进程的集合。通常情况下,他们与同一个作业相关联,可以接收来自同一终端的各种信号。每个进程组有一个唯一的进程组ID,每个进程组都可以有一个组长进程。组长进程的标识是,其进程组ID等于其进程ID。组长进程可以创建一个进程组,创建该组中的进程,然后终止。需要注意的一点就是:只要在某个进程组中一个进程存在,该进程组就存在,这与其组长进程是否终止无关。
&:将进程组放到后台运行
ps选项:
a:不仅列当前用户的进程,也列出所有的其他用户的进程
x:表示不仅列有控制终端的进程,也列出所有的无控制终端的进程
j:表示列出与作业控制相关的信息
从图找那个我们可以看到,进程55755和进程55756同属于一个进程组55755,该进程组中的组长进程是55755进程。下面我们可以用kill命令杀死组长进程55755,但是55756进程依旧存在,所以该进程组55755是依旧存在的。
作业
shell分前后台来控制的不是进程而是作业(job)或者进程组(Process Group)。一个前台作业可以由 多个进程组成,一个后台也可以由多个进程组成,shell可以运行一个前台作业和任意多个后台作业,这称为作业控制
为什么只能运行一个前台作业?
答:当我们在前台新起了一个作业,shell就被提到了后台,因此shell就没有办法再继续接受我们的指令并且解析运行了。
但是如果前台进程退出了,shell就会有被提到前台来,就可以继续接受我们的命令并且解析运行。
作业与进程组的区别:如果作业中的某个进程有创建了子进程,则该子进程是不属于该作业的。
一旦作业运行结束,shell就把自己提到前台(子进程还存在,但是子进程不属于作业),如果原来的前台进程还存在(如果这个子进程还没有终止),他将自动变为后台进程组。
举例说明:
#include <stdio.h>
#include<unistd.h>
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id == 0)
{
//子进程
while(1)
{
printf("child:%d running!\n",getpid());
sleep(1);
}
}
else
{
int i = 5;
while(i)
{
printf("parent:%d going to dead\n",getpid());
i--;
sleep(1);
}
}
return 0;
}
运行结果如下图:
从上图我们可以看到,当程序运行以后,5s以内,shell无法接受我们的命令去解析运行,说明此时的前台作业不是shell。当5s过去以后,父进程会退出,这时我们就发现shell可以接受我们的命令取解析运行它,这就说明父进程退出以后,shell有被提到前台来,变成了前台作业。
我们新起的作业结束了,但子进程还在,就自动被提到了后台运行,可以看到还一直在打消息(杀掉即可)。子进程叔叔的父进程也还存在。组长进程是父进程但是已经退出了。
会话
会话(Session)是一个或多个进程组的集合。一个会话可以有一个控制终端。建立与控制中短的链接的会话收进程被称为控制进程,一个会话中的几个进程组可被分为一个前台进程组以及一个或多个后台进程组。所以一个会话中,应该包括控制进程(会话首进程),一个前台进程组(通常为bash)和任意后台进程组。
我们可以看到,sleep 2000(58747)和sleep 3000(58748)两个进程属于同一个进程组(58747),也属于同一个会话(55460 SID就是会话ID)。我们可以看一看55460到底指得是谁。
有上图可以看到,55460就是bash。而且两个进程的父进程都是bash。
当我们多打开了几个终端之后就会发现,每打开一个就新建了一个会话。
如上图所示,前3个蓝色框中得是在终端1起的作业,红色框中的实在终端2 新起的作业,绿色框中是在终端3新起的作业。
作业控制
Session与进程组”Shell可以运行一个前台进程和任意多个后台进程”其实是不全面的。在上面就已经说到shell分前后台控制的不是进程而是作业或者进程组,一个前台作业可以由多个进程组成,一个后台作业也可以由多个进程 组成,shell可以同时运行一个前台作业和任意多个后台作业。这称为作业控制。
现在需要明确一点就是,ctrl+c杀掉的是整个作业,而不是杀掉某一个进程。
(1) jobs:查看当前有哪些作业
(2)fg:将某个作业提至前台运行,如果该作业的进程组在后台运行,则提至前台运行,如果该作业处于停止状态,则给进程组的每一个进程发送一个SIGCONT信号是他继续运行,参数1表示第一个信号
(3)ctrl+z:向所有前台进程发SIGTSTP信号,该信号的默认处理动作是使进程停止,以后台作业的形式存在。
(4)bg:让某个停止的作业在后台继续运行,也需要给该作业的进程组的每一个进程 发送SIGCONT信号。