本篇文章主要讲述进程间关系的几个基本概念。从以下几个方面叙述:
- 进程组
- 作业
- 会话
进程组
一个进程除了有一个进程id之外,他还属于一个进程组。进程组是一个或多个进程的集合。通常,它们与同一个作业相关联,可以接受来自同一终端的各种信号。每个进程组有一个唯一的进程组id。每个进程组都可以有一个组长i进程。组长进程的标识是,其进程组id等于其进程id。组长进程可以创建一个进程组,创建该组中进程,然后终止。只要在某个进程组中一个进程存在,则该进程组就存在,这与其组长进程是否终止无关。
其实上面这段话有些抽象,我们来举个例子说明以下:
比如我们在学校里面都会分班,假设现在有一个同学他是第一个报名的,那么给它分配一个学号是1号,他所在的班级是1班,并且他是班长,后来又陆陆续续来了一些同学也被分配到这个班,它们的学号是2,3,……
这个1号同学就是组长进程,这个1班就是进程组,它们的标识符是一样的,后来的进程都属于这个进程组。
如果有一天这个班长退学了,它不上学了,那么这个1号学号就不复存在了,但是1号班级还在,并且里面的剩下其他同学也还在这个班级内。
如果剩下的同学也陆陆续续退学了,直到这个班级还剩下一个人,那么这个班级也还仍然存在。
如果这个班级中所有同学都不上了,一个人也没有了,那么这个班级也就不复存在了。
以上我们可以类比于进程组,进程组长,进程的关系。
总结如下:
- 进程组长id与进程组id相同。
- 进程组长可以终止,但进程组不会因此消失。
- 进程组内只要还有一个进程存在,那么这个进程组就存在。
- 进程组内所有进程终止,这个进程组就不复存在。
举例说明:
写一个死循环,让它保持在r状态。
以下可以查看到我们写的 group进程正在运行。
PPID:父进程的pid,这里是bash
PID:该进程的id。
PGID:该进程所属进程组的id。与该进程的pid一样。
创建多进程试试:
可以看到,该进程组id是15305,进程组长即父进程id是15305,其余子进程都属于该进程组并且id依次是15306…,但是进程组id都是一个。
作业
shell分前后台控制的不是进程而是作业或者进程组。一个前台作业可以由多个进程组成,一个后台也可以由多个进程组成,shell也可以运行一个前台作业和任意多个后台作业。这称为作业机制。
必须要区分:进程组与作业的区别:
如果作业中的某个进程又创建了子进程,则子进程不属于作业。
作业是分前后台运行的
下面我们来演示以下:前后台运行的区别:
前台运行:shell不起作用,被提到了后台运行。
后台运行:shell仍然在前台运行。
看下面的例子:
int main()
{
pid_t id=fork();
if(id==0)
{
while(1){
printf("child(%d)# i am running\n",getpid());
sleep(1);
}
}
else
{
int i=5;
while(i)
{
printf("parent(%d)# i am going to dead...%d\n",getpid(),i--);
sleep(1);
}
}
return 0;
}
先来看演示结果:
可以看到前5秒钟,shell不执行任何命令,,原因是我们的作业被提到了前台执行,shell被放在后台执行。
5秒之后父进程退出之后,子进程还在运行,但是此时shell可以执行了,说明子进程已经被提到了后台,但是还在不断地像屏幕输出信息。
我们再次查看进程id和进程组id:可以看到前5秒,有一个进程组16306,父进程是进程组长,id是16306,子进程是16307。
5秒钟之后,父进程退出,我们刚起地作业已经退出了,但是子进程还在,并且子进程所属的进程组还在。
但是子进程还在一直输出信息,我们尝试杀掉它,首先ctrl+c是不能杀死它的,原因是ctrl+c只能对前台进程有效,但是此时的子进程在后台,所以可以用kill -9命令杀死它。虽然如图所示可以看到,命令是被冲乱的,但是命令已经被输入到缓冲区里去了,只要一个回车就会被执行。
作业控制
jobs:查看当前作业
fg:将后台作业放回前台
bg:将前台作业放置后台并运行
演示以下:
我们先起几个作业并置于后台运行。
然后我们将后台进程切换至前台执行,ctrl+c终止它即可。
再次查看作业,发现作业1,已经被杀死了。
我们再起一个作业在前台执行,然后我们想把他放回后台运行。
首先:ctrl+z,暂停该进程,就会发现该进程已经被放在了后台,但是没有执行,是暂停状态。
bg命令可以让他在后台运行。
会话
会话是一个或多个进程组的集合。一个会话可以有一个控制终端。这通常是登陆到其上的终端设备或伪终端设备。建立与控制终端连接的会话首进程被称为控制进程。一个会话中的几个进程组可被分为一个前台进程组以及一个或多个后台进程组。所以一个会话中,应该包括控制终端,一个前台进程组和任意后台进程组。
可以查看会话id:下图中的SID
那么15959是谁呢?
其实就是bash,就是命令解析器。
bash就是该会话中的控制进程,也是默认的前台进程组。
bash自成进程组,自成作业。
最后,梳理一下我们将之前学过的几个概念串在一起:大概画出了下面这张图。