Linux下的进程控制块(PCB)task_struct

 或许你对于task_struct是感到陌生的,那么你就先要知道task_struct是进程控制块(PCB)在linux下的一个具体的实现就好,如果你不知道什么是进程控制块的话,那就先看进程,然后再一步一步来;
  • 什么是进程?

         在之前的操作系统的课程学习中,给出的定义:进程是程序的一次动态的执行过程。(这样,你真的是能想明白吗?概念确实是比较抽象的,反正之前学习的时候我不是很清楚的)。进程=程序段+数据段+进程控制块。当我再次学习操作系统学习进程的时候,却有了更深层次的认识:
    
        从操作系统的层次:进程是程序的一个执行实例;进程是正在执行的程序;进程是能分配处理机并且由处理机执行的实体。这么一说,没有正在执行的程序就一定不是进程吗?不是。假如在单处理机的系统中,一次只能执行一个进程(也就是说,一次只能有一个进程处于运行状态),那么其他的被加载到内存的程序(已经获得了除处理机之外的所需的全部资源),也是进程。 
    
        从内核的层次:担当分配系统资源(包括内存等)的实体。 进程的两个基本元素是程序代码(有可能被其他进程所共享)和与代码相关联的数据集。其实这里,与“进程=程序段+数据段+进程控制块 ”是一样的。数据集就是指的是数据段和进程控制块。
    
  • 什么是进程控制块?

        为了描述进程的信息,我们引入了进程控制块这个数据结构。在单处理机系统,我们每次只能执行一个进程,我们如何知道是哪个进程在执行?执行完这个进程之后,又需要去执行哪些进程?假如一个进程由于种种原因,需要被中断(不是被杀死),那么之后再来执行此进程的时候,我们怎么会知道之前执行到哪(不可能从头开始执行),等等情形,所以就需要进程控制块。 
    
        通过分析以上的种种情况,我们得出:进程控制块至少应该包含进程标识(是进程的唯一标识,PID),还有进程的优先级,记录进程的上下文信息,记录进程下一次下一条指令的地址,进程中的程序的地址,等等(下文将会给出task_struct结构体的成员)。 
    
        当操作系统要调度某进程去执行时,要从该进程的PCB中查询进程的优先级和现行状态; 当系统调度到某个进程时,要根据PCB中保存的现行信息先去回复现场,然后再去修改进程的状态,根据程序的地址,找到程序的位置,并开始执行; 当进程由于某个原因需要暂停时,就必须将现行状态保存在PCB中,并记录下一条指令的地址。
    
        可见,在进程的整个执行过程中,进程控制块都起着非常重要的作用。下边我们就来剖析Linux下的PCB—task_struct结构体。
    
  • 什么是task_struct?

         task_struct就是Linux下PCB的具体实现,那么现在刨悉一下其中的内容,来更好的懂得起作用:
         TASK_RUNNING:
            处在这个状态的进程,不是在运行就是准备运行,只是等待运行本进程的资源到位。即准备运行的进程只要得到CPU就可以立即投入运行。进程中有一个运行队列run_queue,容纳所有可运行的进程,调度进程时,从中选择一个进程进行执行。当前运行进程一直处于该队列中。
        TASK_INTERRUPTIBLE:
            处于等待队列中的进程,等待到资源分配到时觉醒,也可由其它进程通过信号(signal)或定时中断唤醒,唤醒后进入运行队列 run-queue,等待被调度。
        TASK_ZOMBIE:
            顾名思义,僵尸进程。就如电影里面的僵尸一样,人虽已死(指灵魂),但肉体还活着,处于行尸走肉的状态。僵尸进程表示已释放掉所用的资源(即灵魂已逝),但没有释放本身的PCB(task_struct)。
        TASK_SWAPPING:
            进程页面被交换出内存的进程。
        unsigned long flags(进程标志):
            *PF_ALIGNWARN 打印“对齐”警告信息。
            *PF_PTRACED 被ptrace系统调用监控。
            *PF_TRACESYS 正在跟踪。
            *PF_FORKNOEXEC 进程刚创建,但还没执行。
            *PF_SUPERPRIV 超级用户特权。
            *PF_DUMPCORE dumped core。
            *PF_SIGNALED 进程被信号(signal)杀出。
            *PF_STARTING 进程正被创建。
            *PF_EXITING 进程开始关闭。
            *PF_USEDFPU 该进程使用FPU(SMP only)。
            *PF_DTRACE delayed trace (used on m68k)。
    
    进程调度信息:
        表示当前进程或一个进程允许运行的时间,待到该进程的时间片运行结束,CPU会从运行队列上拿出另一个进程运行。
        need_resched:调度标志
        Nice:静态优先级
        Counter:动态优先级
        重新调度进程时会在run_queue中选出Counter值最大的进程。也代表该进程的时间片,运行中不断减少。
        Policy:调度策略开始运行时被赋予的值
        rt_priority:实时优先级
    标识符(Identifiers)
    PID(process identifier):
        32位无符号整型数据。但最大值取32767。表示每一个进程的标识符。也是内核提供给用户程序的借口,用户程序通过pid操作程序。 
        因为Unix的原因引入还引入了线程组的概念。称为:tgid。一个线程组中的所有线程使用和该线程组中的第一个轻量级线程的pid,被存在tgid成员中。当进程没有线程时,tgid=pid;当有多线程时,tgid表示的是主线程的id,而pid表示每一个线程自己的id。 
    
    进程通信有关信息(IPC:Inter_Process Communication)
    
    unsigned long signal; 
      进程接收到的信号。每位表示一种信号,共32种。置位有效。 
      
    unsigned long blocked; 
      进程所能接受信号的位掩码。置位表示屏蔽,复位表示不屏蔽。 
       
    Spinlock_t sigmask_lock:信号掩码的自旋锁
    
    Long blocked:信号掩码
    
    Struct sem_undo *semundo:为避免死锁而在信号量上设置的取消操作
    
    Struct sem_queue *semsleeping:与信号量操作相关的等待队列
    
    struct signal_struct *sig:信号处理函数
    
    进程信息
    
      Linux中存在多进程,而多进程中进程之间的关系可能是父子关系,兄弟关系。 
      除了祖先进程外,其他进程都有一个父进程,通过folk创建出子进程来执行程序。除了表示各自的pid外,子进程的绝大多数信息都是拷贝父进程的信息。且父进程对子进程手握生杀大权,即子进程时是父进程创建出来的,而父进程也可以发送命令杀死子进程。 
      
    
    时间信息
    
    Start_time:进程创建时间
    
    Per_cpu_utime:进程在执行时在用户态上耗费的时间。
    
    Pre_cpu_stime:进程在执行时在系统态上耗费的时间。
    
    ITIMER_REAL:实时定时器,不论进程是否运行,都在实时更新。
    
    ITIMER_VIRTUAL:虚拟定时器,只有进程运行在用户态时才会更新。
    
    ITIMER_PROF:概况定时器,进程在运行处于用户态和系统态时更新。
    
    文件信息:
    
       
      文件的打开和关闭都是资源的一种操作,Linux中的task_struct中有两个结构体储存这两个信息。
    
    Sruct fs_struct *fs:进程的可执行映象所在的文件系统,有两个索引点,称为root和pwd,分别指向对应的根目录和当前目录。
    
    Struct files_struct *files:进程打开的文件
    
    地址空间/虚拟内存信息
    
      每个进程都有自己的一块虚拟内存空间,用mm_struct来表示,mm_struct中使用两个指针表示一段虚拟地址空间,然后在最终时通过页表映射到真正的物理内存上。
    
    页面管理信息
    
    Int swappable:进程占用的内存页面是否可换出。
    
    Unsigned long min_flat,maj_flt,nswap:进程累计换出、换入页面数。
    
    Unsigned long cmin_flat,cmaj_flt,cnswap:本进程作为祖先进程,其所有层次子进程的累计换出、换入页面数。
    
    对称对处理机信息
    
    Int has_cpu: 进程是否当前拥有CPU
    
    Int processor: 进程当前正在使用的CPU
    
    Int lock_depth: 上下文切换时内核锁的深度
    
    上下文信息:
    
    struct desc_struct *ldt:进程关于CPU段式存储管理的局部描述符表的指针。
    
    struct thread_struct tss:任务状态段。与Intel的TSS进行互动,当前运行的TSS保存在PCB的tss中,新选中的的进程的tss保存在TSS。
    
    信号量数据成员
    
    struct sem_undo *semundo:
    
      进程每一次操作一次信号量,都会生成一个undo操作。保存在sem_undo结构体中,最终在进程异常终止结束的时候,sem_undo的成员semadj就会指向一个数组,这个数组中每个成员都表示之前每次undo的量。
    
    truct sem_queue *semsleeping: 
      进程在操作信号量造成堵塞时,进程会被送入semsleeping指示的关于该信号量的sem_queue队列。
    
    进程队列指针
    
    struct task_struct *next_task,*prev_task: 
      所有进程均有各自的PCB。且各个PCB会串在一起,形成一个双向链表。其next_task和prev_task就表示上一个或下一个PCB,即前后指针。进程链表的头和尾都是0号进程。 
      
    
    struct task_struct *next_run,*prev_run: 
      由进程的run_queue中产生作用的,指向上一个或下一个可运行的进程,链表的头和尾都是0号进程。 
     
    
    struct task_struct *p_opptr:原始父进程(祖先进程) 
    struct task_struct *p_pptr :父进程 
    struct task_struct *p_cptr:子进程 
    struct task_struct *p_ysptr:弟进程 
    struct task_struct *p_osptr:兄进程
    
      以上分别是指向原始父进程(original parent)、父进程(parent)、子进程(youngest child)及新老兄弟进程(younger sibling,older sibling)的指针。
    
    current:
    
      当前正在运行进程的指针。 
      
    
    struct task_struct init_task:
    
      0号进程的PCB,进程的跟=根,始终是INIT_TASK。
    
    char comm[16]:
    
      进程正在执行的可执行文件的文件名。
    
    int errno:
    
      进程最后一次出错的错误号。0表示无错误。
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值