Chinaunix首页 | 论坛 | 博客
  • 博客访问: 66826
  • 博文数量: 21
  • 博客积分: 290
  • 博客等级: 二等列兵
  • 技术积分: 286
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-30 16:16
文章分类
文章存档

2019年(3)

2017年(1)

2012年(17)

我的朋友

分类: LINUX

2012-04-05 01:32:07

     我们经常看到 read 的时候没有数据可读,而有时却是 write 的时候缓冲区已
 
满写不进去。而应用程序不关心这个,只关心我要的数据何时能读取出来,或者我
 
写的数据何时才能写进去。因此这样应该要阻塞进程,直到有数据可读或者有内存
 
可写。那我们就来看看几个概念和问题:
 
    1)何为进程睡眠?
   
    2)是否什么情况下都可以睡眠?
 
    3)既然睡眠了,如何唤醒?
 
    4)如何操作阻塞I/O?
   
    1、所谓进程睡眠:当一个进程的状态被置为睡眠之后,它将等待运行的队列中
 
除,一直到该状态被改变,否则它将不会在任何的 CPU 上运行。简单的说睡眠的
 
程将得不到进程调度程序调度,让出 CPU,被搁置到系统的一边。
 
    2、看完了睡眠,那我们也来看看哪些情况不可以睡眠,为什么呢?在<
 
备驱动程序>>中,指出:当你运行在原子上下文时不能睡眠。而原子操作包含有
 
旋锁、BKL、RCU、seqlock、中断上下文。到了这里,大家有个疑惑,那信号量为
 
可以睡眠呢?那我们先来看看原子操作的概念吧,从字面来看,它应该采用了物
 
学的物质微粒的概念,应该是不可再分的操作啊==>所谓原子操作,就是该操作绝
 
会在执行完毕前被任何其他任务或事件打断(连中断也不行吗?),也就说,它的
 
小的执行单位,不可能有比它更小的执行单位。在单核 CPU 中,原子操作至少保
 
了两点:<在SMP中,我不是很清楚,就不多做解释了,若有人知道,可告知哦>
 
    1)原子操作是最小的执行单位,一口气执行完毕,任何打断都无效;
    
    2)保护了共享资源的完整性,不被破坏。
 
    自旋锁禁止CPU抢占,而信号量允许CPU抢占。在单 CPU 情况下,若持有自旋锁
 
进程进入睡眠,由于禁止了CPU抢占,其他进程将永远得不到CPU执行,将唤不醒
 
自旋锁,你说那系统岂不进入睡眠状态啊。那中断呢?能否唤醒自旋锁睡眠呢?一
 
般而言,中断程序能正常运行,但在中断程序中几乎不会做唤醒自旋锁的可能(除
 
非专门设计),所以系统也将处于睡眠状态。而对SMP就不同了,因为各自的CPU执行
 
各自的程序,而自旋锁只是禁止自己的CPU抢占而又当前睡眠而已,所以SMP可以唤
 
醒自旋锁,但是这样做,还是比较危险的啊!!而信号就不同了,它允许CPU抢占。
 
    中断一般操作就是进入中断后,就把关掉中断,直到中断结束再重启中断。若
 
我们关了本地中断后睡眠,任何一个操作中断IO的进程都会睡眠,一旦唤醒之后,
 
多个进程为了抢占资源而并发,从而会导致共享数据的破坏,更有甚者将造成进程
 
死锁啊。
 
     到了这里,应该知道了为何原子操作不能睡眠了吧,两方面:一方面不要进程
 
睡眠,结果导致了系统睡眠或造成死锁,另一方面是保护共享资源。
 
     3、有了睡眠,当然就要有唤醒啦。要不睡眠将毫无意义,因为睡眠只是为了
 
等候到自己所要的东西,取到东西必须返回啊。比如说:你等到的有数据,你一高
 
兴就屁颠屁颠的跑了,哪里还会在那里傻等啊;同时你好不容易等到有内存写进去
 
啦,当然马上写入,然后就跑出去玩了。
 
     4、睡眠IO操作方法: 
       
     使用睡眠IO需要考虑的三个问题:什么情况需要睡眠?什么情况得唤醒?
 
何要睡眠?
 
  1. #include <linux/wait.h>
  2. 第一步:【定义等待队列头并初始化】
  3. /* <动态申请等待队列>
  4.  * @brief             初始化等待队列头
  5.  * @param[in]        queue 我们所要等待的队列
  6.  * @return            no
  7.  */
  8. //wait_queue_head_t my_queue;                    /*定义等待队列*/
  9. init_waitqueue_head(wait_queue_head_t *queue);   /*初始化*/
  10. /*<静态申请等待队列>
  11.  * @brief             初始化等待队列头
  12.  * @param[in]        queue 我们所要等待的队列
  13.  * @return            no
  14.  */
  15. DECLARE_WAIT_QUEUE_HEAD(wait_queue_head_t *queue);

  16. 第二步:【有条件的睡眠】
  17. [NOTE]看你要选择哪种睡眠方式,还有一种无条件睡眠方式这里没介绍
  18. /*
  19.  * @brief     不可中断的睡眠
  20.  * @param[in] queue 我们所要等待的队列《注意它是"通过值"传递的》
  21.  * @param[in] condition 条件是一任意的布尔表达式;它不应当有任何边界效应.
  22.  * @return    添加成功返回 0;      
  23.  */
  24. wait_event(queue, condition)

  25. /*
  26.  * @brief             可中断的睡眠
  27.  * @param[in]        queue 我们所要等待的队列《注意它是"通过值"传递的》
  28.  * @param[in] condition 条件是一任意的布尔表达式;它不应当有任何边界效应.
  29.  * @param[in] timeout 等待一段有限的时间后睡眠
  30.  * @return        
  31.  */
  32. wait_event_timeout(queue, condition, timeout)

  33. /*
  34.  * @brief     可中断的睡眠
  35.  * @param[in] queue 我们所要等待的队列《注意它是"通过值"传递的》
  36.  * @param[in] condition 条件是一任意的布尔表达式;它不应当有任何边界效应.
  37.  * @return    添加成功返回0;若中断返回-ERESTARTSYS         
  38.  */
  39. 【说明】它被唤醒不单单是condition条件为真的时候,还有中断的时候。
  40. wait_event_interruptible(queue, condition)

  41. wait_event_interruptible_timeout(queue, condition, timeout)

  42. 第三步:【睡眠的唤醒】
  43. /*
  44.  * @brief             唤醒给定队列的所有进程
  45.  * @param[in]        queue 我们所要等待的队列《注意它是"通过值"传递的》
  46.  * @return            no
  47.  */
  48. 【注意】若唤醒多个进程,则会产生竞态。Q:要如何进行处理呢?
  49. void wake_up(wait_queue_head_t *queue);

  50. /*
  51.  * @brief             唤醒给定队列的可中断的所有进程
  52.  * @param[in]        queue 我们所要等待的队列《注意它是"通过值"传递的》
  53.  * @return            no
  54.  */

  55. void wake_up_interruptible(wait_queue_head_t *queue);

点击(此处)折叠或打开


 

 

 

 

 


阅读(1111) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~