等待队列——休眠与唤醒

原创 2012年03月29日 20:58:29

内核中的休眠是通过等待队列来处理的。等待队列是一个由正在等待某个事件发生的进程组成的一个简单链表。在内核用wait_queue_head_t来表示。

定义:

DECLARE_WAITQUEUE()(静态定义)

init_waitqueue_head()(动态定义)

在内核中实现休眠的方法有点复杂,实现的模板如下:


/*qisthewaitqueuewewishtosleepon*/

DEFINE_WAIT(wait);

add_wait_queue(q,&wait);//这个函数调用是可选

while(!condition){/*conditionistheeventthatwearewaitingfor*/

prepare_to_wait(&q,&wait,TASK_INTERRUPTIBLE);

if(signal_pending(current))

/*handlesignal*/

schedule();

}

finish_wait(&q,&wait);

一个进程执行如下步骤将自己加入到一个等待队列中:

  • 通过宏DEFINE_WAIT()来创建一个等待队列项。

  • 通过函数add_wait_queue()将该项加入到一个等待队列中。当等待的事件(条件)为真时,等待队列会唤醒该进程项。当然,需要在其他地方调用wake_up()函数。

  • 调用prepare_to_wait()函数将进程的状态改为TASK_INTERRUPTIBLETASK_UNINTERRUPTIBLE。该函数也会在必要的时候将进程加回到等待队列中,在后续的迭代中会用到(提示:第二个步骤可选,因为该函数在任务列表为空的时候也会将当前任务项加入到等待队列中)。

  • 如果状态设置为TASK_INTERRUPTIBLE,,一个信号会唤醒该进程。这称为伪休眠。因此要检测和处理信号。

  • 当进程被唤醒,它再次检测条件是否为真。如果为真,它会退出循环。否则,再次调用schedule()然后重复上述过程。

  • 当条件为真,该进程会将其状态设为TASK_RUNNING并将自己通过finish_wait()从等待队列中删除。

一个例子:

staticssize_t inotify_read(struct file *file, char __user *buf,

size_t count, loff_t *pos)

{

structfsnotify_group *group;

structfsnotify_event *kevent;

char__user *start;

intret;

DEFINE_WAIT(wait);


start= buf;

group= file->private_data;


while(1) {

prepare_to_wait(&group->notification_waitq,&wait,TASK_INTERRUPTIBLE);


mutex_lock(&group->notification_mutex);

kevent= get_one_event(group, count);

mutex_unlock(&group->notification_mutex);


if(kevent) {

ret= PTR_ERR(kevent);

if(IS_ERR(kevent))

break;

ret= copy_event_to_user(group, kevent, buf);

fsnotify_put_event(kevent);

if(ret < 0)

break;

buf+= ret;

count-= ret;

continue;

}


ret= -EAGAIN;

if(file->f_flags & O_NONBLOCK)

break;

ret= -EINTR;

if(signal_pending(current))

break;


if(start != buf)

break;


schedule();

}


finish_wait(&group->notification_waitq,&wait);

if(start != buf && ret != -EFAULT)

ret= buf - start;

returnret;

}

另一种模板:

/*Helper thread */

staticint

my_thread(void*unused)

{

/**

  *                wait_queue_t wait;

  *                init_waitqueue_entry(&wait, current);

  */

DECLARE_WAITQUEUE(wait,current);


daemonize("my_thread");

add_wait_queue(&my_thread_wait,&wait);


while(1) {

/*Relinquish processor until event occurs */

set_current_state(TASK_INTERRUPTIBLE);

if(signal_pending(current))

/*##handlesingalevent##*/

schedule();

/*Control gets here when the thread is woken

upfrom the my_thread_wait wait queue */


/*Quit if let go */

if(pink_slip) {

break;

}

/*Do the real work */

/*... */


}


/*Bail out of the wait queue */

__set_current_state(TASK_RUNNING);

remove_wait_queue(&my_thread_wait,&wait);


/*Atomically signal completion and exit */

complete_and_exit(&my_thread_exit,0);

}

唤醒

通过函数wake_up()唤醒,它将唤醒所有在特定等待队列上等待的进程。一般情况下默认的唤醒函数为:default_wake_function()。它会调用try_to_wake_up(),将被唤醒的进程状态设置为TASK_RUNNING,然后调用enqueue_task()将该进程加入到红黑树中,如果被唤醒的进程的优先级大于当前进程的优先级,设置need_resched1。休眠与唤醒之间的关系如下:

\

伪唤醒是指进程是因为接收到某个信号而被唤醒,而不是等待事件发生而导致其被唤醒。


在最新的内核代码中,一般会使用更高层的接口:wait_eventwait_event_timeout接口。使用wake_up_all唤醒所有添加到某个等待队列链表中的等待队列。使用模板如下:


1. 初始化一个等待队列头:

 

  init_waitqueue_head(&ret->wait_queue);

 

  注: 判断队列是否为空: waitqueue_active(...), 返回false即表示队列为空.

 

2. 等待某个条件发生:

 

   wait_event(...) 或 wait_event_timeout(...)

 

3. 唤醒队列

 

   wake_up_all(...)

 



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Linux 进程控制——等待队列详解

一、什么是睡眠     对于一个进程"睡眠"意味着什么? 当一个进程被置为睡眠, 它被标识为处于一个特殊的状态并且从调度器的运行队列中去除. 直到发生某些事情改变了那个状态, 这个进程将不被在任何 ...

等待队列的简单使用

一、什么是等待队列     1、概念         等待队列是一种实现阻塞和唤醒的内核机制,很早就作为一个基本的功能单位出现在Linux内核中,它以队列为基础数据结构,与进程调度机制紧密结合,能够用...

linux poll 和 等待队列休眠的关系

说明:linux版本2.6.37.1 结合相关资料的概括和总结,在此做个记录,有误之处请网友指正,谢谢! 1.poll机制和等待队列 应用层通过系统调用poll函数进入内核,内核执行...

linux内核的 等待队列 使用方法,wait_queue_head_t,进程休眠

以下来自:http://www.yuanma.org/data/2006/1207/article_1916.htm 假设我们在 kernel 里产生一个 buffer,user 可以经由read,...

linux内核的 等待队列 使用方法,wait_queue_head_t,进程休眠

当你在用户空间需要读写一大片数据的时候,这个就用上了。   以下来自:http://www.yuanma.org/data/2006/1207/article_1916.htm 假设我们在 ke...

linux进程的休眠(等待队列)

当进程以阻塞的方式通信,在得到结果前进程会挂起休眠。 为了将进程以一种安全的方式进入休眠,我们需要牢记两条规则: 一、永远不要在原子上下文中进入休眠。 二、进程休眠后,对环境一无所知。唤醒后,必...

linux进程的休眠(等待队列)

当进程以阻塞的方式通信,在得到结果前进程会挂起休眠。 为了将进程以一种安全的方式进入休眠,我们需要牢记两条规则: 一、永远不要在原子上下文中进入休眠。 二、进程休眠后,对环境一无所知。唤醒后,必...

驱动学习之——内核等待队列的使用

在中,结构体定义如下: struct __wait_queue_head { spinlock_t lock; struct list_head task_list; }; type...

linux 等待队列

  • 2013-03-27 16:02
  • 65KB
  • 下载

Linux的等待队列介绍

  • 2014-05-10 18:35
  • 15KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)