第8章--阻塞与非阻塞IO

一、阻塞与非阻塞I/O

阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作。
被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。
而非阻塞操作的进程在不能进行设备操作时,并不挂起,他要么放弃,要么不停地查询,直到可以进行操作为止。

二、等待队列

在Linux驱动程序中,可以使用等待队列(Wait Queue)来实现阻塞进程的唤醒。
Linux内核提供了如下关于等待队列的操作。

  1. 定义“等待队列头部”

    wait_queue_head_t my_queue;
    
  2. 初始化“等待队列头部”

    void init_waitqueue_head(wait_queue_head_t *q);
    DECLARE_WAIT_QUEUE_HEAD(name)    //定义并初始化等待队列头部
    
  3. 定义等待队列元素

    DECLARE_WAITQUEUE(name, tsk)
    
  4. 添加/移除等待队列

    void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
    void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
    
  5. 等待事件

    wait_event(queue, condition)  //等待queue作为等待队列头部的队列被唤醒,且condition必须满足,否则继续阻塞
    wait_event_interruptible(queue, condition)  //可以被信号打断
    wait_event_timeout(queue, condition, timeout)  //在等待超时时间timeout到达时,无论condition是否满足,均返回
    wait_event_interruptible_timeout(queue, condition, timeout)
    
  6. 唤醒队列

    void wake_up(wait_queue_head_t *queue);  //唤醒以queue作为等待队列头部的队列中所有的进程
    void wake_up_interruptible(wait_queue_head_t *queue);  //只能唤醒处于TASK_INTERRUPTIBLE的进程
    
  7. 在等待队列上休眠

    void sleep_on(wait_queue_head_t *q);  //与wake_up()成对使用
    void interruptilbe_sleep_on(wait_queue_head_t *q);  //与wake_up_interruptible()成对使用
    

三、轮询操作

1. 轮询的概念与作用

使用非阻塞I/O的应用程序通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的访问。
select()和poll()系统调用最终会使设备驱动中的poll()函数被执行。

2. 应用程序中的轮询编程

应用程序中最广泛用到的是select()系统调用,其原型为:

int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  • readfds、writefds、exceptfds分别是被select()监视的读、写和异常处理的文件描述符集合,numfds的值是需要检查的号码最高的fd加1。
  • readfds文件集中的任何一个文件变得可读,select返回;同理,writefds文件集中的任何一个文件变得可写,select也返回。
  • timeout参数是一个指向struct timeval类型的指针,他可以使select()在等待timeout时间后若仍然没有文件描述符准备好则超时返回。

3. 设备驱动中的轮询编程

设备驱动中poll()函数的原型是:

unsigned int (*poll)(struct file *filp, struct poll_table *wait);

第1个参数为file结构体指针,第2个参数为轮询表指针。这个函数应该进行两项工作。

  • 对可能引起设备文件状态变化的等待队列调用poll_wait()函数,将对应的等待队列头部添加到poll_table中。
  • 返回表示是否能对设备进行无阻塞读、写访问的掩码。

poll_wait()函数的原型如下:

void poll_wait(struct file *filp, wait_queue_heat_t *queue, poll_table *wait);

这个函数并不会引起阻塞。poll_wait()函数所做的工作是把当前进程添加到wait参数指定的等待队列中,
实际作用是让唤醒参数queue对应的等待队列可以唤醒因select()而休眠的进程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值