《深入理解linux内核》读书笔记 (二): 进程task_struct详解

进程,轻量进程,线程

对于进程,我们知道一般进程,轻量进程,以及thread。

进程就是一个具有一定功能的程序执行的一次过程(动态的程序)。每一个进程都有自己的独立内存空间,

线程是进程的实体,
轻量级进程,本质上也是一个进程,只是在现代linux中,用它来实现了线程。

进程描述符:

我认为要学习进程,了解了进程描述符的内容后,基本上你就已经了解了进程。
首先,我们还是看图:

对于这张图,看着都眼花是不,确实是这样的,不然我为什么说了解了这个结构后,进程就基本了解了。linux的进程描述符,用task_struct结构体来表示。
该结构体中包含了当前进程的执行状态,进程优先级,以及那些地址是分配给该进程的等等信息,所以复杂就不言而喻了撒(看linux源代码中struct task_struct只是定义就用了280行~~)。
其中,我将在本本博客中,围绕这个图进行阐述。

state字段:

只要我们看见这个名字相信就知道该区域就是表示进程当前状态。
TASK_RUNING:表示进程进程正在运行或者是一切就绪等待cpu分配时间片。
TASK_INTERRUPTIBLE: 直到对应的条件实现,否则进程被挂起。比如等待一个硬件中断,或者是什么系统资源,或者是发出相应的信号,条件满足后都将唤醒进程,并且将进程state段设置为TASK_RUNING.
TASK_UNINTERRUPTIBLE:和TASK_INTERRUPTIBLE不同,除了接受到信号,不然状态不会改变。
TASK_STOPPED:当进程接收到SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU信号,那么进程进入该状态。
TASK_TRACED:进程被debugger所暂停
当进程执行结束后,进程状态保存在state字段和exit_state字段中
EXIT_ZOMBIE: 当进程执行结束后,但是并没有父进程在监听(waitpid()系统调用),那么该进程将进入该状态
EXIT_DEAD:最后的状态了,马上就要灰飞烟灭。

PID字段:

对于内核来说,通过一个指向进程描述符的指针,就可以唯一标识一个进程,相应的操作系统也提供给用户用来标识唯一进程的字段就是PID字段。
考虑到要遵从标准,linux推出了使用进程组的概念。为的就是使多个轻量级进程实现的线程,能够在调用getpid()这样的系统调用的时候能够返回同一个值,所以增加了tgid这样一个字段,让同一个进程里面的线程都有这个字段并且相同,而getpid()这样的系统调用获取的是tgid字段的值。

thread_info和kernel stack 字段:

对于每一个进程,linux都会保存两个不同的数据在都应的空间,一个便是thread_info该结构是指向task_struct的一个指针,另一个是当进程切换到内核态时候的栈空间。如图:
将thread_info和stack放在一起的好处就是kernel可以非常方便的获得thread_info的地址,进而找到当前正在cpu运行进程的task_struct等相关信息。

process双向链表:

process链表将所有存在的进程描述符进行链接。


TASK_RUNNING process 双向链表:

因为笔者能力有限哈,这里就只能简单的理解一下:
由于linux中进程有140中优先级,所以使用一个140个大小的数组,元素分别指向一个链表表示在该优先级下面对应的处于task_runing状态的进程描述符。

关于父子关系(real_parent,parent,children,sibling):

real_parent:该指针指向创建当前进程的的进程,或者是当创建者已经消亡后,该指针指向init进程。
parent:一般情况下和real_parent一样,只是当另外一个进程调用了ptrace()系统调用后,可能会改变~~~~~~
child:由当前进程创建的孩子进程链表的头节点
sibling:正如英语意思“兄弟”,它指向它的下一个或者是上一个兄弟。
关系如下:

进程id相关的hash表和链表:

虽然有了双向链表了,我们对进程描述符的加入链表和删除链表都有了很好的效率,但是对于查找效率就非常低且不稳定,在这里linux给出了一个解决方案,首先将进程hash一次后,再进行链式的存储,如图
上面只是对于pid有hash,对于pgrp,tgid,session呢?当然也是有的。
对于计算机查找过程,如下图


进程等待队列:

前面我们介绍了task_running状态的进程,他们被组织到了一个链表中,而其他状态的进程该怎么办呢?
对于进程task_stopped,exit_zombie或者是exit_dead状态的进程都是不需要将他们链接成一个特定的链表的,因为他们只会通过pid或者是父进程所使用,没有其他情况使用它。
而对于进程处于task_interruptible或者是task_uninterruptible状态的时候,就要分为多个状态进行讨论了,需要依据不同的事件进行分类。在相应时间发生的情况下,必须迅速的恢复进程。这里我们就引进了等待队列。。。

系统根据不同原因进入等待的进程分成多个队列,比如因为资源缺少而进入等待的进程组成一个队列,或者等待某个时间发生组成另外一个队列。
但是并不是某个事件发生后,就唤醒该队列中的所有睡眠进程。这也就避免了著名的“惊群”问题。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值