进程(3)

2019-07-14 12:24发布

                                     linux系统中进程的组织方式          一个系统中通常可以有数百个数千个进程,相应的也就有这么多的PCB,必须使用一些适当的方式将这些PCB组织起来。进程的组织方式其实大都是数据结构中数据的组织方式。          进程链表:双向循环链表将进程联系起来          struct task_struct          {               struct list_head tasks;               char comm[TASK_COM_LEN];//可执行程序的名字带路径          }           链表的头和尾都是init_task,0号进程的PCB,这个进程永远不会被撤销他被静态分配在内核数据段中。           哈希表:有些情况根据进程的PID导出对应的PCB,顺序扫描效率低下。于是引入哈希表。           linux用一个宏pid_hashfn()将PID转换成表的索引。通过pid_hashfn()可以把进程的PID均匀的散列在哈希表中。给定一个PID寻找其对应的PCB函数           static inline struct task_struct * find_task_by_pid(int pid)           {                  struct task_struct *p, **htable = &pidhash[pid_hashfn()];                  for(p = *htable; p && p->pid != pid; p = pidhash->next)                            return p;             }           pidhash是哈希表,其定义为struct task_struct *pidhash[PIDHASH_SZ];           哈希函数并不能保证PID与表的索引一一对应,因此两个不同的PID散列到相同的索引上引起冲突,采用链地址法来处理冲突的PID。也就是说每一个表项是由冲突的PID组成的双休链表。task_struct 结构中有两个域pidhash_next和pidhash_prev来实现这个链表,同一链中的PID由小向大排列。           就绪队列:把所有可运行状态的进程组成一个双向链表叫做就绪队列           struct task_struct{                struct list_head run_list;                ,,,           }           就绪队列的定义及相关操作在/kernel/sched.c文件中           static LIST_HEAD(runqueue_head);//定义就绪队列的头指针为runqueue_head           static inline void add_to_runqueue(struct task_struct *p)           {                  list_add_tail(&p->run_list, &runqueue_head);                  nr_running++;           }           static inline void move_last_runqueue(struct task_struct *p)           {                   list_del(&p->run_list);                   list_add_tail(&p->run_list, &runqueue_head);           }           等待队列:深度睡眠和浅度睡眠两种状态的进程位于同一个等待队列上,等待某些事件不能运行。 等待队列的数据结构           struct __wait_queue           {                 unsigned int flags;                 #define WQ_FLAG_EXCLUSIVE 0x01                 void * private;                 wait_queue_func_t func;                 struct list_head task_list;           };             typedef struct __wait_queue wait_queue_t;             typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key);           task_list把处于睡眠状态的进程连接成双向链表。睡眠是暂时的唤醒才是目的,设置了func域,该域指向唤醒函数,用于吧队列中的进程唤醒。flags域为了区分睡眠时的互斥进程(1)和非互斥进程(0)。private域是传递给func函数的参数。 等待队列头         struct __wait_queue_head        {                 spinlock_t lock;                 struct list_head task_list;        };        typedef struct __wait_queue_head wait_queue_head_t;        等待队列是由中断处理程序和主要的内核函数修改的,因此必须对其双向链表进行保护以免同时访问,通过lock自旋锁进行同步,task_list域是等待进程链表的头