原创 linux内核编程之阻塞、非阻塞和异步

2007-11-27 15:24 5400 7 7 分类: MCU/ 嵌入式

看了前面的几篇介绍,大家应该有了内核编程的基本技能了。现在和大家一起分享一下我对驱动程序中阻塞操作、非阻塞操作和异步处理的理解。


1。阻塞操作


     在内核空间,比如我们要做个数据采集系统,AD转换没有结束之前,是无法从AD的数据寄存器读取数据的。这样驱动程序就会停留在查询AD结束标志的死循环中,读进程被阻塞。
     在用户空间,用户的程序在打开设备后,调用读取驱动的缓冲区,以获取AD转换结果。而驱动程序被阻塞后,用户的read函数也同样无法返回。其实在此时CPU已经被100%的占用了。占用CPU的不是用户代码,而是内核驱动中的读AD结果的函数。
    通过对比用户和内核空间可知,这种阻塞操作会严重浪费CPU资源,并影响其他进程的执行,降低系统的效率。
    为了解决这个问题,阻塞操作中引入了等待队列。驱动程序检测到有阻塞操作,也就是上文提到的AD结果没有出来时,调用interrupt_sleep_on函数,让读操作进入睡眠。这样CPU就可以闲置出了完成其他工作而不是先前的查询AD标志了。等待AD转换结束后,再唤醒读进程(谁完成了唤醒的任务,在此讲有些早,慢慢看大家就知道了),这样就能够返回AD结果了。
   说完内核空间,再看看用户空间,其实在用户空间的代码没有丝毫改变。阻塞问题本来就不是用户程序产生的,解决当然不用改变用户代码。当用户程序调用read,读取AD结果时,内核驱动调用等待队列,进入睡眠,用户程序在read处停止,等待内核唤醒后的返回值。和前面相比,此时的CPU不是被占着的!


2。非阻塞操作


    对于非阻塞操作,内核驱动在检测到没有AD值时,会立即返回,而不是等待AD结果的出现。其余的内容与阻塞操作一样。
   提到非阻塞操作,就不得不提select函数。通俗的说select函数就是询问数据是否准备就绪。如果select函数发现AD结果已经出来了,就会返回成功,否则调用等待队列。 举个例子:
             if(select())
                  阻塞read();
            这个例子是永远不会被阻塞的,你应该明白其中的道理了吧:)


3。异步触发机制


    为了解决一些慢的输入设备,比如键盘。控制台的执行需要接收键盘指令,而又不能总是查询键盘的缓冲区(这样会发生阻塞,浪费CPU)。就需要一种类似于中断的机制,这就是异步触发。当键盘的缓冲区中有数据时,会发送信号给进程。异步触发到底和中断程序有什么关系,我还没有学习到中断部分。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
7
关闭 站长推荐上一条 /3 下一条