linux操作系统原理与应用-读书笔记(2)-进程(1)

时间:2023-01-06 10:41:44

1。进程控制块-进程状态

  Linux的设计中,考虑到在任一时刻在CPU上运行的进程最多只有一个,而准备运行的进程可能有若干个,因此为了管理上的方便,把就绪状态和运行状态合并为一个状态--可运行态。

linux操作系统原理与应用-读书笔记(2)-进程(1)

2。进程控制块-进程标识符(PID

  PID是一个32位的无符号整数,顺序编号,最大号是32767

3。进程控制块-进程之间的亲属关系

 linux操作系统原理与应用-读书笔记(2)-进程(1)

  task_struct{

      long state;

      int pid, uid, gid;

      struct task_struct *parent, *child, *o_sibling, *y_sibling; /*亲属关系*/

  }

4。进程控制块-进程控制块的存放

  Linux把每个进程的PCB和内核栈放在一起,占用8KB的内存区。C语言表示如下:

  union task_union{

      struct task_struct task;

      unsigned long stack[2408];

  };

  Linux调用alloc_task_struct()函数分配8KBtask_union内存区,调用free_task_struct()函数释放它。内核栈的大小不能超过7KB

  PCB与内核栈放在一起的好处:

  1)内核可以方便而快速地找到PCB

       p = (struct task_struct *) STACK_POINTER & 0xffffe000

       PCB的起始地址总是开始于页大小的边界。

  2)避免在创建进程时动态分配额外的内存。

5。进程的组织方式-进程链表

  包含所有的进程,使用task_struct *prev_task, *next_task;

  链表的头和尾都为init_task0号进程的PCB),这个进程永远不会被撤销它的PCB被静态的分配到内核数据段中,也就是说init_taskPCB是预先由编译器分配的,在运行的过程中保持不变。而其他的PCB是在运行的过程中由系统根据当前的内存状况随机分配的,撤销时归还给系统。

  遍历链表用for_each_task()

  #define for_each_task(p) /

        for (p = &init_task ; (p = p->next_task) != &init_task; )

6。进程的组织方式-散列表

  使用PID查找比较低效,引入散列表。散列函数为:

  #define pid_hashfn(x) /

        ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))

  PIDHASH_SZ为表中元素的个数。

 linux用链地址法来处理PID引起的冲突,也就是说,每一个表项都是由冲突的PID组成的双向链表,task_struct结构中有两个域pidhash_next 和 pidhash_pprev 用来实现这个链表,同一个链表中pid由小到大排列。

  对于一个给定的pid,可以通过find_task_by_pid()函数快速地找到对应的进程:

  static inline struct task_struct *find_task_by_pid(int pid){

    struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];

    for(p = *htable; p && p->pid != pid; p = p->pidhash_next);

    return p;

  }

7.进程的组织方式-可运行队列

  一个双向循环链表,链表头为init_task。

8。进程的组织方式-等待队列

  1)暂停态或僵死态的进程不链接在专门的链表中,也没有必要把它们分组,因为父进程通过进程的PID或进程间的亲属关系可以检索到这些子进程。

  2)把TASK_INTERRUPTIBLE 或 TASK_UNINTERRUPTIBLE状态的进程分为一类,每一类对应一个特定的事件,对应一个等待队列。

  等待队列的结构:

  struct wait_queue{

    struct task_struct * task;

    struct wait_queue * next;

  };

  3)sleep_on()

  sleep_on(struct wait_queue *q){

    struct wait_queue wait;

    wait.task = current;

    current->state = TASK_UNINTERRUPTIBLE;

    add_wait_queue(q, &wait);

    schedule();

    remove_wait_queue(q, &wait);

  }

  4)如果要唤醒等待的进程,就调用唤醒函数wake_up(),它让等待唤醒的进程进入TASK_RUNNING状态。