进程间关系——进程组、作业、会话

进程组:

每个进程除了有自己的进程ID之外,还属于一个进程组。

进程组是一个进程之间的集合,由一个或多个进程组成。通常是为了共同完成某一项任务,所以相应的,同一进程组中的进程可以接受来自同一终端的各种信号。

每个进程组有一个唯一的组ID,有一个进程组组长。作为进程组的组长,他有一个很明显的特征可以让我们认出他,那就是:进程组ID和进程 ID相同。

函数getpgrp可以返回调用进程的进程组ID:

#include<unistd.h>

pid_t getpgrp(void);

组长进程可以创建一个进程组,创建改组中的进程,然后终止。只要在某个进程中还有一个进程存在,那么该进程组就还存在。进程组的存在与否与进程组组长是否终止无关。

某个进程组的最后一个进程可以终止,也可以转移到其他进程组。

从进程组创建开始到其中最后一个进程离开为止的时间区域称为进程组的生命期。

进程调用setpgid可以加入一个现有的进程组或者创建一个新进程组。

#include<unistd.h>

int setpgid(pid_t pid,pid_t pgid)

setpgid函数将pid进程的进程组ID设置为pgid。如果这两个参数相等,则由pid指定的进程变成进程组组长。如果pid是0,则使用调用者的进程ID。另外,如果gpid是0,则由pd指定的进程ID用作进程组ID。

作业:

Shell分前后台来控制的不是进程而是作业,或者也可以说是进程组。一个前台作业可以有多个进程组成,一个后台作业也可以由多个进程组组成。Shell可以运行一个前台作业和多个后台作业,这被称为作业控制。

作业与进程的区别:

如果作业中的某进程又创建了子进程,那么该子进程不属于该作业,但属于进程组。

一旦作业运行结束,Shell就把自己提到前台 ,如果原来的前台进程还在,它自动变为后台进程组。

或者我们可以重新理解为i:在前台新起作业,Shell是无法运行的,因为它被提到了后台,但是如果前台进程退出,Shell就又被提到了前台,所以可以继续接受用户的输入。

会话:

SID:会话ID。

会话是一个或多个进程组的集合,一个会话可以有一个控制终端。

进程调用setsid函数建立一个新会话:

#include<unistd.h>

pid_t setsid(void);

如果该调用进程已经是一个进程组的组长,则此函数返回出错。为了保证不处于这种情况,通常先调用fork创建出一个子进程,然后令其父进程终止,再让子进程继续。因为子进程继承了父进程的进程组ID,而其进程ID则是重新分配的,两者不可能相等,这就保证了子进程不可能是一个进程组的组长。

函数getsid返回会话首进程的进程组ID:

#include<unistd.h>

pid_t getsid(pid_t pid);

如果pid是0,getsid返回调用进程的会话首进程的进程组ID。出于安全方面的考虑,一些实现有以下限制:

如果pid并不属于调用者所在的会话,那么调用进程就不能得到该会话首进程的进程组ID。

建立与控制终端相连接的会话首进程被称为控制进程。

一个会话中几个进程组可以被分为一个前台进程组以及一个或多个后台进程组。所以一个会话中,应该包含控制进程,一个前台进程组和任意多个后台进程组。

注意:若是kill-9删掉当前会话的前台作业,终端会退出,但会话还在。

新建一个终端就是打开一个会话。

猜你喜欢

转载自blog.csdn.net/weixin_36229332/article/details/80042453