等待队列(转)

需要让进程睡眠的原因是要等待某些条件的满足,这时可以让进程进入睡眠状态,等设备可以进行读写操作时再将其唤醒。对此,内核提供了比较通用的机制,即等待队列。包含在头文件#include<linux/wait.h>中。

1.定义和初始化

    定义一个变量:wait_queue_head_t wq;实际上,这个数据类型内部包含了一个双向循环链表,用来存放正在等待的进程信息。在使用前需将其初始化,使用接口函数:

    void init_waitqueue_head(wait_queue_head_t *q);

还可以直接定义并初始化,这要用到一个宏:DECLARE_WAIT_QUEUE_HEAD(wq);

等待队列也有一个初始化符,可以用它对变量进行初始化,例如

   wait_queue_head_t wq=__WAIT_QUEUE_HEAD_INITIALIZER(wq);

2.等待

让进程开始等待的最基本操作如下:wait_queue(wq,condition);

其中,wq是进程要加入的等待队列,注意这里只是一个宏,不需要等待队列的指针就可以操作它。参数condition则是一个条件表达式。该宏的基本功能如下:让进程进入等待状态,直到条件condition满足为止。

   使用这个接口时,当前进程进入不可被信号打断的睡眠态,这种状态下的进程,即使向它发送KILL信号也不能将其中止,多数情况下这并不是想要的结果。为让进程在等待时仍能响应信号,可使用以下接口:

   wait_event_interruptible(wq, condition);

   wait_event_killable(wq, condition);

这两个宏与wait_event功能相似,唯一不同是当前进程将进入可被信号打断的睡眠状态,当有信号发生时,进程将被激活继续运行。因此,它有一个返回值以区别被唤醒和被信号激活两种情况:返回0表示当前进程是通过等待队列被唤醒的,这种情况只有当condition成立才有可能发生;返回错误码-ERESTARTSYS时表示是被信号激活的,这时condition不一定成立。

   另一接口可让当前进程等待一定的时间后自动恢复运行:

   wait_event_timeout(wq,condition,timeout);

  使用这个接口时,当前进程将进入不可被信号打断的睡眠态,但是当睡眠的时间超过timeout指定的时间间隔时,进程将自动醒过来,实际上是由一个内核定时器唤醒的。这个接口的返回值表示进程醒来时离设定的时间还有多久。当返回0时,表示是因为超时而醒来的,这时condition不一定成立;当返回非零值时,表示是通过等待队列被唤醒的,这时condition一定成立。

  还有一个接口综合了可被信号打断及超时限制两个特征,如下:

  wait_event_interruptible_timeout(wq,condition,timeout);

它的返回值也是前两者的综合,返回正数或零表示进程醒来时离设定超时还有多久,返回错误码-ERESTARTSYS表示是被信号激活的。

  进程还有一种特殊的开始等待的方式,称为排他式的等待。以这种方式入队将影响唤醒操作的行为,如下

  wait_event_interruptible_exclusive(wq,condition);

3.唤醒

  void wake_up(wait_queue_head_t *q);

  它的功能是唤醒q指向的等待队列中所有以非排他方式入队的进程,对于以排他方式入队的进程则只唤醒第一个。

  void wake_up_all(wait_queue_head_t *q);

  唤醒等待队列中的所有进程,不管是以排他方式还是非排他方式入队的。

  也可以只唤醒那些可被信号打断的进程,如下:

  void wake_up_interruptible(wait_queue_head_t *q);

  这个函数依然只能唤醒第一个以排他方式入队的进程。如要唤醒所有可被信号打断的进程,使用如下接口:

  void wake_up_interruptible_all(wait_queue_head_t *q);

posted @ 2012-07-30 11:28  Drobobls  阅读(161)  评论(0)    收藏  举报