linux进程管理(2)---进程的组织结构

一、目的

    linux为了不同的进程管理目的,使用了不同的方法组织进程之间的关系,为了体现父子关系,使用了“树形”图;为了对同一信号量统一处理,使用了进程组;为了快速查找某个进程,使用了哈希表;为了进程调度,创建了运行队列、等待队列,将不同运行状态的进程放入不同的队列中。

    本文将讲述进程间的组织方式及特点。


二、父子关系、兄弟关系

    系统启动后创建第一个进程0swapper,也叫idle)和进程1init),之后进程0进入idle状态,当没有进程可以被调度的时候运行该进程,不做具体的事情;系统其它的进程都是由进程1创建的,所以进程1自然而然就是系统所有进程的父进程,系统进程之间的关系也就呈现出“树形”结构。

    进程1还负责处理僵尸进程。由于进程0不具备处理僵尸进程的能力,所以不能为进程1创建兄弟进程,否则当进程1的兄弟进程处于僵尸态时,系统就无法处理这些僵尸进程了。

    当一个进程创建新进程时,默认新进程是当前进程的子进程;当前进程是新进程的父进程。当使用CLONE_PARENT参数标志创建新进程时,当前进程和新进程拥有相同的父进程。

    当两个进程之间是父子关系时,父进程的children成员连接了所有子进程;子进程的sibling成员连接了该子进程的所有兄弟进程(即父进程的所有子进程),real_parent成员指向实际的父进程,parent成员指向了实际处理子进程SIGCHLD信号的进程。

    使用ps命令的-H参数可以显示进程的父子关系。例如,在当前bash下新建子进程bash,并在子进程bash中创建子进程ps,使用ps-H命令显示效果如下:



三、进程组

    在《linux进程管理(1---进程描述符》的第三节详述了linux下进程与进程组的概念,为了满足POSIX标准,linux提出了进程组的概念;多个进程合作完成一个功能,那么这些进程可以放到一个进程组中。

    每个进程组都会指定一个进程为“组长”;“组员”通过使用group_leader成员指向“组长”;同时,“组长”使用thread_group成员将“组员”组织起来。

    使用进程组可以解决系统给一组进程发送同一信号量的场景,在该场景下,系统只需给“组长”发送信号量即可,所以处于同一进程组的进程之间共享信号量资源。

    默认情况下,新进程独自组成了一个进程组并且承担“组长”的责任;如果使用CLONE_THREAD参数标志,指定新进程与当前进程处于同一进程组,那么,此时当前进程与新进程之间不存在父子关系(实际上,新进程指向当前进程的父进程),但是这两个进程拥有相同的“组长”,所以,在这种情况下,从进程组的角度才能准确表达进程之间的关系。

    使用ps命令的-eLf参数可以查看进程组关系,显示结果中PID表示进程组ID(注意,此时PID的含义是tgid)、PPID表示父进程IDLWP表示进程IDNLWP表示进程组中进程的个数。

    例如,使用ps -eLf命令后,可以看到rsyslogd进程组有四个“组员”(即四个线程),“组长”的pid821,“组员”的pid分别是821844895896821“组员”也是该组的“组长”。


    默认情况下proc文件系统显示的是进程组“组长”的文件夹,使用ps-eLf命令找到进程组“成员”的pid(对应轻量级进程的pidLWP),然后直接在proc目录下cdpid文件夹中即可。


四、哈希表

    为了快速查找某个进程,系统将所有进程连接在一个全局的链表中,表头是init进程的tasks成员;当一个进程被创建时,会将该进程的tasks成员链接到init进程的tasks中。

    所以,从当前进程出发,向上寻找父进程,一直找到init进程为止;那么就可以从init进程的tasks成员链表找到任意一个进程。

    使用ps命令的-AL参数可以显示所有进程,包括轻量级进程。


五、运行队列、等待队列

    调度程序使用运行队列和等待队列管理进程的调度,处于运行队列中的进程满足调度条件,随时等待调度程序将其放入cpu运行;处于等待队列中的进程由于缺乏某个资源而睡眠,当条件满足时被放入运行队列中。

    运行队列管理的是处于运行态的进程,等待队列管理的是睡眠态的进程(可中断态和不可中断态),其他状态的进程(退出态、停止态等)因为和系统调度无关,所以不会放入队列中管理。因此,只有运行态和睡眠态的进程才会被放入队列中。

    处于运行态的进程具有不同优先级,根据优先级又可以把进程放到不同优先级的运行队列中。

    等待队列是linux比较常用的数据结构,在很多地方都使用该结构,例如:中断处理、进程同步等场景。处于睡眠态的进程可能因为不同的事件而阻塞,所以根据事件类型又可以把进程放到不同事件的等待队列中。


六、全景视图

    为了有个直观的感受,给出一幅进程组织关系的全景视图。

    从图中可以看出,内核进程idle有两个孩子kthreaddinitinit进程有三个孩子ksyslogd,并且这三个孩子组成了一个进程组,“组长”是进程826,“组员”是进程845、进程887;此时,有一个等待队列,队列中有两个成员,分别指向了进程845、进程887



七、总结

    为了管理进程的创建、消亡(处理僵尸进程等操作)使用了父子、兄弟关系;为了统一处理同一信号量,使用进程组关系;为了方便全局查找,使用了哈希表关系;为了调度程序,使用了运行队列、等待队列数据结构。

    我们不仅要掌握这些进程组织关系的具体含义,更重要的是思考linux精心设计这些组织关系背后的“驱动力”和技巧。当我们以后遇到类似场景时,能够“拿来主义”为我所用。


版权声明:

    原创作品,如非商业性转载,请注明出处;如商业性转载出版,请与作者联系。

linux进程管理(2)---进程的组织结构,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。