等待队列(阻塞与非阻塞)

IO阻塞和非阻塞模型: 
http://blog.csdn.net/sun172270102/article/details/52672917

https://www.cnblogs.com/lubiao/p/4858086.html 
等待队列的实现原理实质是利用了内核线程的等待状态属性,也就是说它是一个有睡眠属性的内核线程。 
有个bug,驱动在release时候,去撤销线程的时候发现这个线程(内核队列)一直卡在那里即阻塞在那里,导致CPU被消耗,串口也死了,没有反应。 
原因查明是因为这个线程里有个while(1)死循环,而这个循环中还有个等待队列。 
这个等待队列做了一个超时等待,等待被wakeup,由于这个等待队列没有被唤醒,而超时又时间很长所以导致一直阻塞在这个等待队列里,从而导致 
这个线程也被阻塞,线程撤销的时候就没有反应。

note:线程退出时要把该清理的资源清理干净,不然会像这次一样程序死在这里。 
另外,在线程里使用while(1)循环时,需要在while(1)里面加上一个msleep()让空出时间片 
等待队列只是线程阻塞的一种方式;

    

等待队列和工作队列一样,都有一个内核缺省的等待对列,同时也可以自己创建一个等待队列 
这里有两个概念,一个是等待队列,使用结构体wait_queue_t表示,一个是等待项,使用结构体wait_queue_head_t表示,等待项可以等同于工作队列中task的概念。 
等待项需要添加进等待队列,就像task需要添加进工作队列一样,是队列中的成员和队列的关系。

一,使用内核缺省的等待队列

 
  1. 1 wait_queue_head_t my_queue; 定义一个等待项
  2. 2, init_waitqueue_head(&my_queue)初始化一个等待项,用这个api初始化的时候已经将这个等待项加入了内核缺省的等待队列
  3. 或者直接使用宏DECLARE_WAIT_QUEUE_HEAD(my_queue);  来定义和初始化还有绑定这个等待项到内核缺省的等待队列
  4. 3wait_event(queue, condition) ;(别在中断里面搞)condition为唤醒条件,在一个函数里面等待:
  5. 4wake_up(wait_queue_head_t *queue); 在另一个函数里面唤醒:

二,自己创建一个等待对列

 
 
  1. 1 wait_queue_t my_wait; 定义一个等待队列
  2. 2 init_wait(&my_wait);初始化这个等待队列,或者直接使用宏DEFINE_WAIT(my_wait);来初始化这个等待队列
  3. 3 wait_queue_head_t wait_head; 定义一个等待项
  4. 4 add_wait_queue()将等待项加入到自己创建的这个等待队列,添加到等待队列中去之后,不会进入睡眠等待
  5. 5 remove_wait_queue()从等待队列中移走这个等待项,删除唤醒以后的等待项
  6. 6wait_event(queue, condition) ;(别在中断里面搞)condition为唤醒条件,在一个函数里面等待:
  7. 7wake_up(wait_queue_head_t *queue); 在另一个函数里面唤醒:

常用阻塞接口:

 
 
  1. wait_event(wq, condition) 退出阻塞条件为condition为真
  2. wait_event_timeout(wq, condition, timeout) 退出阻塞条件为condition为真或者超时时间到
  3. wait_event_interruptible(wq, condition) 退出阻塞条件为condition为真或者被消息唤醒
  4. wait_event_interruptible_timeout(wq, condition, timeout) 退出阻塞条件为condition为真或者超时时间到或者被其他消息唤醒

常用唤醒接口:

 
 
  1. wake_upwait_queue_head_t *queue
  2. wake_up_interruptible(wait_queue_head_t *queue)
  3. wake_up_all

如何唤醒等待项: 
任何一个wake族函数都会触发一个task,去遍历这个所属的等待队列上的所有睡眠的等待项,然后会去检查每个睡眠进程所关联的wake_up和wait_event中的condition,如果为为真,就将该进程置为TASK_RUNING属性让其继续执行。其他不满足的则继续睡眠。

所以唤醒的条件是: 
1.condition 这些条件要置为真 
2,使用wake_up族函数去唤醒等待队列

关于wait_event_timeout

http://bbs.chinaunix.net/thread-3615327-1-1.html

 
 
  1. do {
  2.         DEFINE_WAIT(__wait);
  3.         for (;;) {                /* break可以退出 */
  4.                 prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);
  5.                 if (condition)
  6.                         break; 
  7.                 ret = schedule_timeout(ret);
  8.                 if (!ret)/* 若timeout为等完,则进入下一次循环继续等 */
  9. break; /* 若timeout超时,退出 */ 
  10.         } 
  11.         finish_wait(&wq, &__wait);

schedule_timeout有两种情况退出: 1. wake_up; 2. timer超时;

wake_up会把schedule_timeout打断,此时schedule_timeout注册的定时器并未超时,schedule_timeout直接返回,回到for(;循环,这个循环只有break才能推出,而break有两种情况: 1. 条件为真; 2. ret==0,也就是超时;

如果调用wake_up而condition不为真,则再次调用schedule_timeout,不过此时传入的时间,是上次剩余的时间,当其超时时,wait_event_timeout同样会执行到break退出,所以不会无限的执行下去:

 
 
  1. wait_event_timeout - sleep until a condition gets true or a timeout elapses
  2. * @wq: the waitqueue to wait on
  3. * @condition: a C expression for the event to wait for
  4. * @timeout: timeout, in jiffies
  5. *
  6. * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the
  7. * @condition evaluates to true. The @condition is checked each time
  8. * the waitqueue @wq is woken up.
  9. *
  10. * wake_up() has to be called after changing any variable that could
  11. * change the result of the wait condition.
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值