进程(2)

来源:互联网 发布:清华大学网络教学本科 编辑:程序博客网 时间:2024/05/17 01:09

                                   LINUX系统中的进程控制块

       进程的信息在LINUX中通过内核中的一个结构体来描述-task_struct.这样的数据结构被叫做PCB进程控制块。对进程信息的描述包括进程当前的状态,进程的优先级,他正在占用CPU还是阻塞,给他分配了什么地址空间,他可以访问那个文件等等。

        PCB是一个相当大的结构,他的域主要分为以下几类

       【1】状态信息-描述进程动态的变化,比如就绪态、等待态、僵死态等。

       【2】连接信息-描述进程的亲属关系,比如父进程,祖父进程,子进程,兄弟进程等。

       【3】各种标识符-用简单数字对进程进行标识-PID,UID等

       【4】进程间通信信息-描述多个进程在同一任务上协作工作-管道,消息队列,共享内存,套接字等

       【5】时间和定时信息-描述进程在生存周期内使用CPU时间的统计、计费等信息

       【6】调度信息-描述进程优先级调度策略等

       【7】文件系统信息-对进程使用文件情况进行记录,如文件描述符,系统打开文件表。用户打开文件表

      【8】虚拟内存信息-描述每个进程拥有的地址空间,也就是进程编译连接后形成的空间

      【9】处理器环境信息-描述进程的执行环境(处理器的各种寄存器及堆栈等等),这是体现进程动态变化的主要场景。

        下面通过一些简单的例子说明PCB中这些域的使用,,,,,,,

        当内核调度某进程执行时要从该进程的PCB中查出其运行状态和优先级。在某进程被投入运行时要从其PCB中取出其处理器的环境信息,恢复其运行现场。在进程运行过程中需要与其合作的进程实现同步、通信或者访问文件时,也要访问其PCB。当进程因某种情况而暂停执行时,又需将其断点的处理机环境保存在PCB中。PCB是进程存在和运行的唯一标识。

       PCB的创建和回收

       当系统创建一个进程时,就为他建立一个PCB进程结束时又收回其PCB,进程也随之消亡。PCB是内核中被频繁读写的数据结构故应常驻内存。

        LINUX下进程的状态:

        LINUX下因为运行态只有一个进程,故将运行态和就绪态合并为就绪态

        (1)就绪态:正在运行或者准备运行,处于这个状态的所有进程组成就绪队列

        (2)等待态:深度睡眠和浅度睡眠

                 浅度睡眠:进程被阻塞,等待资源有效时被唤醒也可以有其他进程通过时钟或者信号唤醒。

                 深度睡眠:被阻塞,其他进程发的时钟中断和信号不能打断她的睡眠

        (3)暂停状态:暂停执行,比如进程收到一些信号时(SIGSTOP停止进程执行、SIGTSTP从终端发来的信号停止进程、SIGTTIN键盘的中断、SIGTTOU后台进程请求输出)

        (4)僵死状态:进程执行结束但尚未消亡-此时进程的大部分资源已经释放但尚未释放其PCB。

          struct   task_struct

          {

              volatile long state;//确保状态变化可以及时反映出来

              .......

          }

       进程标识符

         每个进程都有进程标识符、用户标识符、组标识符

         进程标识符(PID):内核通过PID来识别不同的进程,同时他也是OS提供给用户的一个接口,用户程序通过PID对进程发号施令。新建进程的PID通常是上一个进程PID加1.LINUX上允许最大PID号由pid_max来指定。当内核在系统中创建的PID大于这个值时就要重新使用已闲置的PID号。如果是大型服务器可以让管理员更改pid_max的值

         每个进程都属于某个用户组,task_struct中有UID和GID。系统通过这两种标识符控制进程对系统中文件和设备的访问。

         进程的亲缘关系

         struct task_struct

         {

                volaile long state;

                int pid,gid,uid;

                struct task_struct * realparent;

                struct task_struct * parent;

                struct list_head  children;//子进程链表

                struct list_head sibling;//兄弟进程链表

                struct task_struct *group_leader;//线程组头进程

                。。。

            }

            进程控制块的存放

            每当进程从用户态进入内核态后都要使用栈,这个栈叫做进程的内核栈。当进程一进入内核态,cpu就自动设置该进程的内核栈,这个栈位于内核的数据段上。LINUX把内核栈和一个紧接PCB的小数据结构thread_info放在一起占用8KB.

           union  thread_union{

               struct thread_info thread_info;

               unsigned long stack[THREAD_SIZE/sizeof(long)];

           }

          

           struct thread_info

           {

               struct task_struct * task;

               struct exec_domain *exec_domain;

          }

          从用户态切换到内核态只要把数据写入栈中,则堆栈寄存器的指针就向箭头方向递减。p表示thread_info的其实地址而task又是thread_info的第一个数据项,故只要找到thread_info就能很容易的找到当前运行的task_struct了。

        内核根本不给PCB分配内存而只是给内核栈分配8KB的内存PCB占用了其中的一部分。

         当前进程

         thread_info和内核栈放在一起的最大好处是内核很容易通过ESP寄存器获得当前CPU上运行的thread_info结构的地址。

         current_thread_info()函数获得thread_info的基地址,因为thread_union结构的长度是8kb,则内核屏蔽ESP的低13为有效位就可以获得thread_info结构的基地址。

         struct task_struct *currentpcb = current_thread_info()->task;

          

         struct task_struct *myparent = current->parent;

 

       

0 0
原创粉丝点击