linux 下的进程控制块-task_struct 初学

来源:互联网 发布:淘宝账号登录阿里妈妈 编辑:程序博客网 时间:2024/06/14 04:27

<span style="font-family:SimSun;font-size:18px;"></span>
进程控制块PCB(Process Control Block)

(1)概述

进程控制块的作用是使一个在多道程序环境下不能独立运行的程序(含数据),成为一个能独立运行的基本单位,一个能与其它进程并发执行的进程。或者说,OS是根据PCB来对并发执行的进程进行控制和管理的。 PCB通常是系统内存占用区中的一个连续存区,它存放着操作系统用于描述进程情况及控制进程运行所需的全部信息,它使一个在多道程序环境下不能独立运行的程序成为一个能独立运行的基本单位,一个能与其他进程并发执行的进程。

(2)基本内容:

      进程控制块(PCB)(系统为了管理进程设置的一个专门的数据结构,用它 来记录进程的外部特征,描述进程的运动变化过程。系统利用PCB来控制 和管理进程,所以PCB是系统感知进程存在的唯一标志。进程与PCB是一 一对应的)。是进程存在和运行的唯一标志,在Linux中用task_struct这个结构体来表示。进程在操作系统中都有一个户口,用于表示这个进程。这个户口操作系统被称为PCB(进程控制块),这个结构体中有很多数据项,查看源代码时没必要理解全部的数据项,只需要在以后使用时再理解。理解为进程在操作系统中都有一个户口,用于表示这个进程。这个户口操作系统被称为PCB(进程控制块),在linux中具体实现是 task_struct数据结构,它记录了一下几个类型的信息:

1.状态信息,例如这个进程处于可执行状态,休眠,挂起等。

2.性质,由于unix有很多变种,进程有自己独特的性质。

3.资源,资源的链接比如内存,还有资源的限制和权限等。

4.组织,例如按照家族关系建立起来的树(父进程,子进程等)。

(3)应用:

在不同的操作系统中对进程的控制和管理机制不同,PCB中的信息多少也
不一样,通常PCB应包含如下一些信息。

1、进程标识符name:每个进程都必须有一个唯一的标识符,可以是字符串,也可以是一个数

2、进程当前状态 status:说明进程当前所处的状态。为了管理的方便,系统设计时会将相同的状态的进程组成一个队列,如就绪进程队列,等待进程则要根据等待的事件组成多个等待队列,如等待打印机队列、等待磁盘I/O完成队列等等。

3、进程相应的程序和数据地址,以便把PCB与其程序和数据联系起来。
4、进程资源清单。列出所拥有的除CPU外的资源记录,如拥有的I/O设备,打开的文件列表等。

5、进程优先级priority:
进程的优先级反映进程的紧迫程度,通常由用户指定和系统设置。

6、CPU现场保护区cpustatus:当进程因某种原因不能继续占用CPU时(如等待打印机),释放CPU,这时就要将CPU的各种状态信息保护起来,为将来再次得到处理机恢复CPU的各种状态,继续运行。

7、进程同步与通信机制 用于实现进程间互斥、同步和通信所需的信号量等。

   8、进程所在队列PCB的链接字 根据进程所处的现行状态,进程相应
的PCB参加到不同队列中。PCB链接字指出该进程所在队列中下一个进程
PCB的首地址。
   9、与进程有关的其他信息。 如进程记账信息,进程占用CPU的时间等。

(4)实例:

Linux task_struct

在linux 中每一个进程都由task_struct 数据结构来定义. task_struct就是我们通常所说的PCB。
struct task_struct{    long state; /*任务的运行状态(-1 不可运行,0 可运行(就绪),>0 已停止)*/    long counter;/*运行时间片计数器(递减)*/    long priority;/*优先级*/    long signal;/*信号*/    struct sigaction sigaction[32];/*信号执行属性结构,对应信号将要执行的操作和标志信息*/    long blocked; /* bitmap of masked signals */    /* various fields */    int exit_code;/*任务执行停止的退出码*/    unsigned long start_code,end_code,end_data,brk,start_stack;/*代码段地址 代码长度(字节数)                                    代码长度 + 数据长度(字节数)总长度 堆栈段地址*/    long pid,father,pgrp,session,leader;/*进程标识号(进程号) 父进程号 父进程组号 会话号 会话首领*/    unsigned short uid,euid,suid;/*用户标识号(用户id) 有效用户id 保存的用户id*/    unsigned short gid,egid,sgid; /*组标识号(组id) 有效组id 保存的组id*/    long alarm;/*报警定时值*/    long utime,stime,cutime,cstime,start_time;/*用户态运行时间 内核态运行时间 子进程用户态运行时间                           子进程内核态运行时间 进程开始运行时刻*/    unsigned short used_math;/*标志:是否使用协处理器*/    /* file system info */    int tty; /* -1 if no tty, so it must be signed */    unsigned short umask;/*文件创建属性屏蔽位*/    struct m_inode * pwd;/*当前工作目录i 节点结构*/    struct m_inode * root;/*根目录i节点结构*/    struct m_inode * executable;/*执行文件i节点结构*/    unsigned long close_on_exec;/*执行时关闭文件句柄位图标志*/    struct file * filp[NR_OPEN];/*进程使用的文件表结构*/    /* ldt for this task 0 - zero 1 - cs 2 - ds&ss */    struct desc_struct ldt[3];/*本任务的局部描述符表。0-空,1-代码段cs,2-数据和堆栈段ds&ss*/    /* tss for this task */    struct tss_struct tss;/*本进程的任务状态段信息结构*/};

(5)struct结构的描述:

<span style="font-family:SimSun;font-size:18px;">struct task_struct  {        ....  };  </span>


一、下面重点介绍几个基本的数据项:

1。进程状态

task_struct中用一个长整形state表示进程的状态。


<span style="font-family:SimSun;font-size:18px;">volatile long state;</span>


在linux中有四种基本的进程状态:

(1)就绪态(TASK_RUNNING):包括了运行态的进程。这是为了方便管理,因为任意时刻处于就绪态的进程最多只有一个。

(2)等待(睡眠)态:又被分为两种

      i.浅度睡眠态(TASK_INTERRUPTIBLE): 在两种情况下被唤醒:

                                                         1.当等待的资源满足时。

                                                         2.其它进程通过信号或时钟中断唤醒。

     ii.深度睡眠态(TASK_UNINTERRUPTIBLE):只能等到等待的资源满足时才被唤醒,而不能被其它进程唤醒

 (3)暂停状态(TASK_STOPPED):收到以下几种信号,进程进入暂停状态:

        i.SIGSTOP------------------停止进程执行

        ii。SIGTSTP-----------------从终端发来信号停止进程

       iii。SIGTTIN------------------来自键盘的中断

       iv。SIGTTOU----------------后台进程请求输出。

(4)僵死状态(TASK_ZOMBIE):进程已结束且释放大部分资源,但尚未释放其PCB

2。进程标识符

linux用一个32位无符号整形pid来简单的标识一个进程,用uid和gid分别来标识进程所属的用户和组

<span style="font-family:SimSun;font-size:18px;">pid_t pid;        uid_t uid;  gid_t gid; </span>

pid的上限是由pid_max决定的。编译内核时会让选择0x1000和0x8000两种数值,即pid_max=4096和pid_max=32768两种。

3。亲属关系

<span style="font-family:SimSun;font-size:18px;">struct list_head children;        //子进程链表  struct list_head sibling;        //兄弟进程链表  struct task_struct *real_parent; //真正创建当前进程的进程   struct task_struct *parent;      //养父进程  </span>


二。进程控制块的存放

1.内核栈

当进程从用户态进入内核态时要使用位于内核数据段上的内核栈,

2.数据结构

<span style="font-family:SimSun;font-size:18px;">union thread_union  {           struct thread_info thread_info;           unsigned long stack[THERAD_SIZE/sizeof(long)];//内核栈,一般为8KB  };  </span>

内核中将task_struct的指针放在thread_info结构体中,而这个结构体又与内核栈一块被放在8KB的内核空间thread_union中。

<span style="font-family:SimSun;font-size:18px;">struct thread_info{              struct task_struct *task;              struct exec_domain *exec_domain;              .....    };    </span>


0 0
原创粉丝点击