Linux中的进程关系详解

来源:互联网 发布:自学cg插画知乎 编辑:程序博客网 时间:2024/05/29 07:06

进程组的概念

每一个进程除了有一个进程ID之外,还属于一个进程组,进程组通常是一个或多个进程的集合。这些进程通常是与一个作业相关的。例如:ps axu|grep bash|wc -l 这是三个进程,他们直接通过管道传递数据,为了是完成一个作业,对于这个整体来说是一个进程组,其中ps进程是进程组的组长进程。进程组也是由一个id来标识进程组的,通过使用PGID来标识,然而这个PGID==进程组组长进程的PID的使用下面的这个命令来验证这一事实:

[root@localhost common]# ps -o pid,ppid,pgid,sid,comm|more  PID  PPID  PGID   SID COMMAND 2445  2441  2445  2445 bash 3882  2445  3882  2445 ps 3883  2445  3882  2445 more ps 是其中的第一个进程,也是这个进程组的组长进程,那么其 PID==PGID==2882 more和ps是同一个进程组的,因为其PGID相同

相关的系统API

下面这两个方法是用来设置和获取进程组的方法

#include <unistd.h>int setpgid(pid_t pid, pid_t pgid);如果pid等于pgid,那么pid就成为了其所属的进程组的组长进程,如果pid等于0,则标识把当前进程设置为pgid的组长进程如果pgid等于0,则使用pid作为目标pgidpid_t getpgid(pid_t pid); //这个方法的使用很简单,这里不做介绍

下面是一个测试的例子,在这个例子显示出一个只有单个进程的进程组

#include <unistd.h>#include <stdio.h>int main(){        printf("%d\n",getpgid(getpid()));        while(1);}测试结果如下: a.out属于4082这个进程组的,并且是组长进程[root@localhost ~]# ps -o pid,ppid,pgid,sid,comm a  PID  PPID  PGID   SID COMMAND 1698   815  1698  1698 bash 2445  2441  2445  2445 bash 4082  2445  4082  2445 a.out 4087  4083  4087  4087 bash 4206  4087  4206  4087 ps

可以看出正常情况下,直接运行的进程通常是一个新进程组的组长进程,与这个进程又通信的,或者是这个进程派生的都属于这个进程组.

会话的概念

会话就是一些有关联的进程组的集合而已.概念上来说其实不是很难理解
下面是一个展示会话其含义的例子:

[root@localhost ~]#  ps -o pid,ppid,pgid,sid,comm|more  PID  PPID  PGID   SID COMMAND 4087  4083  4087  4087 bash 4521  4087  4521  4087 ps 4522  4087  4521  4087 more再次使用这个例子,ps 和more进程是一个进程组,bash进程属于另外一个进程组,bash执行了ps和more进程,所以这两个进程组存在关联,属于一个会话。其中SID代表这个会话的ID,从上面的结果可以看书,ps more bash是两个进程组的,但是都是一个会话的。会话ID,为首领进程组的组长进程的PID

相信通过上面的这个例子,你应该对会话有了一个新的概念了吧.

相关的系统API

用于设置和获取session id的API

#include <unistd.h>pid_t getsid(pid_t pid); //获取指定进程的sidpid_t setsid(void);1.不能由进程组的组长进程调用,否则会产生错误2.非进程组的组长进程调用将会创建会话并且会产生下面的效果:    1.调用进程成为会话的首领,此时该进程是新会话的唯一成员    2.新建一个进程组,其PGID为其PID,该进程成为该组的组长进程    3.调用进程讲脱离终端(守护进程中常用)

一个错误使用setsid的例子

#include <unistd.h>#include <stdio.h>int main(){        setsid();        perror("setsid error");        while(1);}setsid error: Operation not permitted[root@localhost ~]#  ps -o pid,ppid,pgid,sid,comm a  PID  PPID  PGID   SID COMMAND 1698   815  1698  1698 bash 2445  2441  2445  2445 bash 4087  4083  4087  4087 bash 4960  2445  4960  2445 a.out 4961  4087  4961  4087 ps

上面的例子会执行失败,其执行失败的原因在于执行这个程序后,这个程序是一个进程组的组长进程,组长进程是无法调用setsid的.下面的例子是一个正确使用setsid的例子:

#include <unistd.h>#include <stdio.h>int main(){        if(fork > 0)                //父进程等待                while(1);        else{        //子进程,创建会话,并创建一个新的进程组成为组长进程                setsid();                while(1)        }} PID  PPID  PGID   SID COMMAND 5070  2445  5070  2445 a.out 5071  5070  5071  5071 a.out

上面的例子中通过在子进程中调用setsid成功创建了一个新的会话,和新的进程组,并且成为了新进程组的组长进程以及会话的领导进程组.子进程之所以可以成功创建会话是因为父进程是进程组的组长进程,子进程只是属于这个进程组中的一个进程而已,除此之外什么也不是,所以这个子进程具备setsid的使用条件.

会话和终端的关系

  • 一个会话可以有一个控制终端(controlling terminal)。
  • 建立与控制终端连接的会话首进程被称为控制进程(controlling process)。
  • 一个会话中的几个进程组可被分成一个前台进程组(forkground process group)和几个后台进程组(background process group)。
  • 如果一个会话有一个控制终端,则它有一个前台进程组。
  • 无论何时键入终端的中断键(DELETE或Ctrl+C),就会将中断信号发送给前台进程组的所有进程。
  • 无论何时键入终端的退出键(Ctrl+),就会将退出信号发送给前台进程组的所有进程。
  • 如果终端检测到调制解调器(或网络)已经断开连接,则将挂断信号发送给控制进程(会话首进程)。
0 0