1.非阻塞模型
在我们使用open函数时,将打开的驱动设置为O_NONBLOCK时,当我们用read函数去读取硬件数据时,无论硬件是否有数据,都会往下执行,不会被阻塞在这里
2.阻塞模型
在我们使用open函数时,没有设置O_NONBLOCK时,当我们用read函数去读取硬件数据时,会被阻塞在read函数位置,直到硬件数据准备就绪,才会解除阻塞。在阻塞的时候,进程会处于休眠态。
休眠态分为两种:
第一种是D uninterruptible sleep (usually IO)//该模式为不可中断休眠态,不能通过外部信号将进程结束。例如:ctrl+c,ctrl+z等
第二种是S interruptible sleep(wating for an event to complete)//该模式为可中断休眠态,能通过外部信号将进程结束。例如:ctrl+c,ctrl+z等
我们可以在终端输入ps -aux 查看各种进程的运行状态
如下图所示:
3.io多路复用
如果一个进程需要同时监听多个硬件的数据,需要用到io多路复用。IO多路复用是基本思想为:在用户空间中将监听的事件文件描述符添加到时间集合中,调用函数进行判断集合中文件描述符对应的硬件数据是否准备就绪,准备就绪后,便将休眠的进程的唤醒。
如果休眠事件没有触发,进程切换为休眠状态(可中断休眠状态)
休眠事件被触发,进程被唤醒,准备对硬件进行读写。
IO多路复用的实现机制有三种:select,poll,epoll
select为将所有的文件描述符放入一个集合当中,如果有触发则唤醒休眠状态
操作集合函数有
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:一颗树、一张表、三个接口