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

一、目的

    linux为了不同的进程管理目的,使用了不同的方法组织进程之间的关系,为了体现进程创建关系,使用了父子关系;为了区分进程和线程,使用了进程组;为了快速查找某个进程,使用了哈希表;为了进程调度,使用了运行队列、等待队列,将不同运行状态的进程放入不同的队列中。

    本文将讲述进程间各种方式及特点。


二、父子关系、兄弟关系

    task_struct real_parent成员指向父进程,parent成员指向“养父进程”;children成员表示该进程的子进程链表;sibling成员表示该进程的兄弟进程链表。

    系统启动后创建了第一个进程:进程0swapper,也叫idle),进程0创建了第一个用户进程(进程1/sbin/init)和第一个内核进程(进程2kthreadd),之后进程0进入idle状态,当没有进程可以被调度的时候运行该进程,不做具体的事情。

    进程1的主要作用是处理僵尸进程。当某个父进程比子进程提前消亡时,父进程会给子进程重新寻找“养父进程”,一般就是进程1,由进程1负责处理该子进程的消亡。


    当创建一个新进程时,新进程的父进程为当前进程或者线程,并且把新进程加入到父进程的子链表中。如果使用CLONE_THREAD标志创建一个新进程时,新进程的父进程为当前进程或线程的父进程,并且把新进程加入到父进程的子链表中。

    当使用CLONE_THREAD标志创建一个新线程时,新线程的父进程为当前线程组长的父进程(保证线程组内所有线程的父进程相同),所以线程组看起来像是一个独立的进程。此时,因为创建的是线程,所以不需要把新线程加入到任何子链表中(进程才涉及到子链表和兄弟链表,而线程不涉及)。


    下面举个例子:进程100创建了新进程101;进程101使用CLONE_THREAD标志创建了新线程102;线程102使用CLONE_PARENT标志创建了新进程103;线程102使用CLONE_THREAD标志创建了新线程104;线程104创建了新进程105

    从图中看出,不管是谁创建一个新线程,那么新线程的父进程永远是线程组长的父进程;不管是谁创建了一个新进程,新进程的父进程永远是当前进程或线程;如果使用了CLONE_PARENT标志,那么新进程与当前进程是兄弟关系,与当前进程拥有相同的父进程。


    使用ps命令的-H参数可以显示进程之间的父子关系或者也可以使用pstree命令。


三、线程组

    每个线程组都会指定一个线程组长;线程使用group_leader指向线程组长;同时,线程组长使用thread_group将线程链接起来。

    当创建一个新进程时,新进程独自组成了一个线程组并且承担线程组长。

    当使用CLONE_THREAD标志创建一个新线程时,新线程的线程组长为当前进程或线程的线程组长。


    下面举个例子,进程100创建了新进程101;进程101创建了新线程102;线程102创建了新线程103。从图中可以看出,新进程是线程组的组长;一个线程组内的所有线程拥有同一个线程组长。


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


四、哈希表

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

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

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


五、运行队列、等待队列

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

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

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

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


六、全景视图

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

    从图中可以看出,进程idle有两个孩子kthreaddinit;进程init有一个孩子ksyslogd,并且这个孩子是进程组长,除了组长还有两个线程:线程845和线程887;此时,有一个等待队列,队列中有两个成员,分别指向了进程845、进程887



七、总结

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

    我们不仅要掌握这些进程组织关系的具体含义,更重要的是思考linux精心设计这些组织关系背后的“驱动力”和技巧。


版权声明:

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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值