linux操作系统二 进程管理

      执行线程,是进程中活动的对象。每个线程拥有一个独立的线程计数器,进程栈和一组进程寄存器。内核调度的是线程而非进程。

1.进程描述符及其任务结构

      内核把进程放在叫做任务队列的双向循环链表中。链表中的每一项都是类型为task_struct,称为进程描述符,其结构定义位于linux/sched.h文件中。进程描述符中包含一个具体进程的所有信息。task_struct在32位机器上,大约有1.7k字节,包含了描述正在执行的程序的相关信息。

1.1分配进程描述符

      linux通过slab分配器分配task_struct结构,这样能达到对象复用和缓冲着色的目的。

      所以只需在系统堆栈栈底创建一个新结构thread_info,该结构中的task域存放指向该任务的task_struct指针。

                  struct thread_info {

                                  struct   task_struct       *task;

                                      struct      exec_domain    *exec_domain;

                                       unsigned   long          flags;

                                       unsigned    long         status;

                                        __u32                        cpu;

                                       __s32                         preempt_count;

                                       mm_segment_t           addr_limit;

                                      structrestart_block    restart_block;

                                       unsigned     long        previous_esp;

                                       __u8                             supervistor_stack[0];

                                                       }

1.2进程描述符的存放

      内核通过一个唯一的标识符PID来标识每个进程,表示为 pid_t隐含类型,实际上是int类型。PID最大默认值为32768.

      内核中大部分处理进程的代码直接通过task_struct进行的,因此通过current宏找到正在运行的进程描述符的速度显得尤为重要,x86结构中,current把栈指针的后13个有效位屏蔽,用来计算threadd_info的偏移。该操作通过current_thread_info来实现,其汇编代码为:

             movl  $-8192, %eax

              andl %esp , %eax

      这里假定栈的大小为8kb,当4kb的栈启用时,就要用4092,而不是8192.最后current再从thread_info的task域中提取并返回task——struct的得知:

               current_thread_info ()->task;

1.3进程状态

      进程描述符的state域描述了当前状态。该域的值必须为下列五种状态标志之一:    

      TASk_RUNNING                      运行吗、,这是用户空间的进程执行的唯一可能状态

      TASK_INTERRUPTIBLE          可中断   进程被阻塞

      TASK_UNINTERRUPTIBLE     不可中断

      TASK_ZOMBIE                         僵死

      TASK_STOP                             停止

1.4设置当前进程状态

      内核经常需要调整某个进程的状态。这时最好使用set_task_state(task, state)函数

         set_task_state(task,state);

1.5进程树

      通过下面的代码获得父进程的进程描述符

       struct task_struct *my_parent=current->parent;

      同样可用一下方式访问子进程

      struct task_struct *task; 

      struct list_head *list;  

 

       list_for_each(list, &current->children) { 

                     task =list_entry(list, struct task_struct, sibling);         /* task 现在指向当前的某个子进程 */ 

                                                                               }

     

      init进程的进程描述符是作为init_task静态分配的。下面的代码可以很好地演示所有进程之间的关系:

      struct task_struct *task;

      for (task = current; task != &init_task;tasktask = task->parent) ;

      /* task 现在指向init */

     

      实际上,你可以通过这种继承体系从系统的任何一个进程出发查找到任意指定的其他进程。但大多数时候,只需要通过简单的重复方式就可以遍历系统中的所有进程。这非  常容易做到,因为任务队列本来就是一个双向的循环链表。对于给定的进程,获取链表中的下一个进程:

       list_entry(task->tasks.next, struct task_struct, tasks)

         获取前一个进程的方法与之相同:

 
 
  1. list_entry(task->tasks.prev, struct task_struct, tasks)

      这两个例程分别通过next_task(task)宏和prev_task(task)宏实现。而实际上,for_each_ process(task)宏提供了依次访问整个任务队列的能力。每次访问,任务指针都指向链表中的下一个元素:

 
 
  1. struct task_struct *task;
  2. for_each_process(task) {
  3. /* 它打印出每一个任务的名称和PID*/
  4. printk("%s[%d]\n", task->comm, task->pid);
  5. }

特别提醒 在一个拥有大量进程的系统中通过重复来遍历所有的进程代价是很大的。因此,如果没有充足的理由(或者别无他法),别这样做。

2.进程创建


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值