Chinaunix首页 | 论坛 | 博客
  • 博客访问: 377748
  • 博文数量: 146
  • 博客积分: 2990
  • 博客等级: 少校
  • 技术积分: 1399
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-09 22:09
文章分类

全部博文(146)

文章存档

2011年(1)

2010年(2)

2009年(143)

我的朋友

分类: LINUX

2009-03-30 19:57:02

2.   等待队列

进程(也就是正在运行的程序)可以转入休眠状态以等待某个特定事件,当该事件发生时这些进程能够被再次唤醒。内核实现这一功能的技术要点是把等待队列(wait queue)和每一个事件联系起来。需要等待事件的进程在转入休眠状态后插入到队列中。当事件发生之后,内核遍历相应队列,唤醒休眠的任务让它投入运行状态。任务负责将自己从等待队列中清除。
等待队列的功能强大得令人吃惊,它们被广泛应用于整个内核中。更重要的是,实现等待队列的代码量并不大。
等待队列,我对他的简单解释就是,他是一个循环链表,每个节点中包含了一个指向等待进程task_struct的指针。等待队列需要一个等待队列头,作为等待队列的起始点。所以我们现来看看等待队列头,其定义在/include/linux/wait.h中:
 struct __wait_queue_head {
          spinlock_t lock;
         struct list_head task_list;
  };
  typedef struct __wait_queue_head wait_queue_head_t;
有两个数据字段:
    lock:防止双向链表被同时访问,所以要使用锁。
    task_list:双向链表。
然后再来看等待队列如何被定义的:
 typedef struct __wait_queue wait_queue_t;
 struct __wait_queue {
         unsigned int flags;
 #define WQ_FLAG_EXCLUSIVE       0x01
         void *private;
         wait_queue_func_t func;
         struct list_head task_list;
};
   flags:101表示互斥进程由内核有选择地唤醒,0表示非互斥进程总是由内核在事件发生时唤醒。
   private:此字段以前为struct task_struct * task,现在改为void *型,但其作用不变,指向一个等待进程。
   func:指向一个函数地址,被用来指定一个在等待队列的睡眠进程如何被唤醒。
   task_list:双向链表。
接着就是他们各自的定义以及初始化:
  等待队列头:
    1struct wait_queue_head_t q_head;//定义
      init_waitqueue_head(&q_head);//初始化
  //init_waitqueue_head(my_queue);代码如下:
  void init_waitqueue_head(wait_queue_head_t *q)
  {
          spin_lock_init(&q->lock);
          INIT_LIST_HEAD(&q->task_list);
  }
   2、快速定义并初始化(静态地)                                  
DECLARE_WAIT_QUEUE_HEAD(name);
  源码如下:
 #define DECLARE_WAIT_QUEUE_HEAD(name) \
    wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) {\                         
.lock = __SPIN_LOCK_UNLOCKED(name.lock),              \
.task_list= { &(name).task_list, &(name).task_list } }
 等待队列:
 静态地定义并初始化: DECLARE_WAITQUEUE(name, tsk)
  #define DECLARE_WAITQUEUE(name, tsk)                                   
 wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
  #define __WAITQUEUE_INITIALIZER(name, tsk) {\                           
          .private        = tsk,              \                                         
          .func           = default_wake_function,\                       
          .task_list      = { NULL, NULL } }
  定义和初始化之后就是对他的基本操作了:
  一、添加等待队列:add_wait_queue();
//linux/kernel/wait.c
 static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
 {
         list_add(&new->task_list, &head->task_list);
 }
   void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
  {
          unsigned long flags;
          wait->flags &= ~WQ_FLAG_EXCLUSIVE;
          spin_lock_irqsave(&q->lock, flags);
          __add_wait_queue(q, wait);
          spin_unlock_irqrestore(&q->lock, flags);
  }
解释:add_wait_queue()将非互斥进程添加到等待队列头所指的等待队列中,若想添加互斥进程则使用
void fastcall add_wait_queue_exclusive(wait_queue_head_t *q,
wait_queue_t *wait),此函数将wait->flags置为
1
(源码为:wait->flags|=WQ_FLAG_WXCLUSIVE;)
  二、移除等待队列:  remove_wait_queue();//linux/kernel/wait.c
  void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
  {
          unsigned long flags;
 
          spin_lock_irqsave(&q->lock, flags);
          __remove_wait_queue(q, wait);
          spin_unlock_irqrestore(&q->lock, flags);
  }
  static inline void  __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old)
 {
         list_del(&old->task_list);
 }
以上操作只是描述了等待队列本身的一些操作,并非是利用他来实现
管理任务的。
阅读(670) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~