驱动IO三种模型
非阻塞IO:
当在应用程序中读取硬件数据时,不管硬件数据有没有准备好,read()函数不会阻塞住,而是继续向下执行。
在应用程序中用open函数以非阻塞的方式打开文件,会直接使用驱动程序中的mycdev_read()函数的内容
阻塞IO:
当在应用程序中读取硬件数据时,如果硬件数据没有准备好,那么此时阻塞在read()函数位置,直到硬件数据准备就绪,通过read()读取硬件数据,应用程序向下执行,进程阻塞等待硬件数据此时处于休眠态。
特点:比较简单,只能监听一个硬件的数据,效率低。
在应用程序中使用open函数设置为阻塞状态,在硬件数据没有准备好的时候(condition标志量为0),将进程的task_struct添加到等待队列(先要定义等待队列再初始化等待队列)(wait_queue_head wq_head),将进程切换为休眠状态(可中断休眠\不可中断休眠)(wait_event\wait_event_interuptible)。当硬件数据准备好时将condition置1并唤醒进程(wake_up\wake_up_interruptible)
IO多路复用:
想要在一个进程中同时监听多个硬件的数据,就需要使用IO多路复用。实现机制有三种:select 、poll 、epoll。IO多路复用的基本思想是在用户空间中将监听的事件文件描述符添加到事件集合中,调用函数进行判断集合中文件描述符对应的硬件数据是否准备就绪,如果没有一个事件发生,将进程切换到休眠状态(可中断休眠状态)。当有一个或者多个硬件数据准备好了,将休眠的进程唤醒,对准备好的硬件数据进行读写。
特点: 1> 在单进程单线程的情况下,同时处理多个硬件数据输入输出请求。
2> 由于不需要创建新的进程和线程,减少系统的资源开销,减少上下文切换的次数。
Selec:阻塞函数,让内核检测指定文件描述符集合中,是否有文件描述符准备就绪
当文件描述符准备就绪后,该函数解除阻塞。
当事件产生后,集合中会只剩下触发事件的文件描述符。
操作集合函数有:
void FD_CLR(int fd, fd_set *set); 将fd从集合中剔除
int FD_ISSET(int fd, fd_set *set); 判断fd是否在集合中,在返回真,不在返回假
void FD_SET(int fd, fd_set *set); 将fd加入到集合中
void FD_ZERO(fd_set *set); 清空集合
Poll:阻塞函数,让内核检测指定文件描述符集合中,是否有文件描述符准备就绪
当文件描述符准备就绪后,该函数解除阻塞。
Epoll:一颗树、一张表、三个接口
三者区别:
select:监听的文件描述符有限制,Linux系统默认是1024
poll:和select差不多, 比select优越的地方是监听的文件描述符个数可以不限
epoll:
1) 监听的文件描述符个数不限
2) select/poll有事件时,会无差别遍历所有文件描述符,依次判断是否有数据,复杂度为O(n); 而epoll 会把哪个流发生了怎样的I/O事件通知我们,复杂度为O(1)。显然epoll优势明显。(具体用法google一下)