1、进程组
每个进程除了自己本身的ID之外,还属于一个进程组。进程组(Process Group)是一个或多个进程的集合。
- 进程组ID等于组长进程的进程ID,组长进程可以创建一个进程组
- 每个进程组都有一个组长进程,如果组长进程终止,只要该进程组内还存在至少一个进程,则该进程组就存在,与其组长进程是否终止无关
进程组通常与作业相关联,同组内的进程可以接收来一同一终端的同一信号
创建一个前台进程组
注意:我们在前台执行的都是一个进程组或者说是作业(./可执行文件
产生的是一个作业/进程组),而不是单独的进程
前面信号机制中所说的Ctrl-C
等信号终止的是前台进程组
重新开启一个终端查看当前的前台进程信息
红圈表示的PGID
就是进程组ID的意思
刚才创建的前台进程组中的进程有着同样的进程组ID:32585
在按下`Ctrl-C`后,该进程组被直接终止
ps
选项:
a
:不仅列当前用户的进程,也列出所有其他用户的进程x
:表示不仅列出控制终端的进程,也列出所有无控制终端的进程j
:表示列出与作业控制相关的信息
2、作业
上面说过,我们在进行./可执行文件
操作时产生的是一个作业或进程组,而不是单独的进程。一个前台作业可以由多个进程组成,后台进程也是如此,后台作业可以同一时间存在多个,前台作业在一个终端下只能存在一个。
作业(Job)和进程组的区别:如果作业中的某个进程又创建了子进程,子进程不属于该作业,但是属于该进程组
下面用一段代码解释两者区别
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
int i = 5;
if(pid < 0)
{
perror("fork");
return -1;
}else if(pid == 0)
{//子进程
while(1)
{
//子进程一直打印该语句
printf("I am Running,I am child %d \n",getpid());
sleep(1);
}
}else{
//父进程打印完五秒后退出
while(i)
{
printf("I am father, %d \n",i--);
sleep(1);
}
}
return 0;
}
- 执行
a.out
后,产生了一个前台作业,shell被切换到后台,此时不可以接收命令,五秒后,父进程退出,红线画出的命令提示框表示shell又被切换到了前台,可以接收命令,但是刚才创建的子进程在后台仍持续在打印消息,可以看出该子进程不属于刚才的作业,不然应该随父进程一并退出才对
- 这是之后又执行了一次并在另一个终端下查看的结果,可以看出父进程和子进程是同属与一个进程组的,父进程退出后,子进程仍属于这个进程组,但是变成了孤儿进程,并被1号进程回收,想要它不再向屏幕打印消息,直接用
kill -9 +进程ID
杀死就好
刚才演示中可以看出,shell在运行前台作业时,它会自动跳到后台,所以我们在执行自己的程序时,shell是无法接收用户输入的命令的。一但前台作业结束后,shell又被切换到了前台。
前台作业与后台作业
- 前台作业可以接收用户的命令,也可以输出结果,但一个终端下只能执行一个前台作业,后台作业可以有多个
- 后台作业只可以输出结果,不可以接收用户输入,Linux下刚才演示过了,Windows下同样也如此,比如我们在做其他工作是,后台可以挂起QQ,可以播放音乐,我们还可以把屏幕分开,一半放视频,一半写作业(我经常这么干,哈哈),但是你每次只能操作一个界面,不可能又去控制视频播放,同时又把歌曲切换了。
‘&’
:加在执行文件的后面,表示将该作业放到后台执行
jods
:显示当前后台作业
fg 1
:将1号作业放到前台执行,这时shell就会被切换到后台
3、会话
会话(Session)是一个或多个进程组的集合。
一个会话应该中,应该包括控制进程(会话首进程),一个前台进程和任意后台进程组
- 一个会话可以有一个控制终端。这通常是登陆到其上的终端设备(在终端登陆情况下)或伪终端设备(在网络登陆情况下)。
- 建立与控制终端连接的会话首进程被称为控制进程,一般是bash解释器。
- 一个会话中的几个进程组可被分为一个前台进程组以及多个后台进程组。
启用刚才的例子
SID
:会话ID:32605
,可以看出一个进程组的所有进程都属于这个会话,其实这个终端下执行的所有进程都属于该会话(守护进程除外,最下面的SID为702的即为守护进程,守护进程自成会话)
该进程组的所有进程又有同样的父进程32605
,我们来看一下该进程是谁
果不其然,该进程就是我们的bash,会话首进程。会话ID也就是我们的会话首进程的进程ID。