打印

IO 的阻塞和非阻塞一:等待队列

[复制链接]
221|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
冰糖炖雪梨|  楼主 | 2018-8-22 10:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再

进行操作。被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。



阻塞,默认的形式简单直接效率低

非阻塞,相反,占用资源比较多



阻塞从字面上听起来似乎意味着低效率,实则不然,如果设备驱动不阻塞,则用户想获取设

备资源只能不停地查询,这反而会无谓地耗费 CPU 资源。而阻塞访问时,不能获取资源的进程将

进入休眠,它将 CPU 资源“礼让”给其他进程。



IO 的阻塞用的是 等待队列

非阻塞用的是 轮询





介绍:以队列为基础数据结构,与进程调度机制紧密结合,能够用于实现内核中的异步事件通知机制,也可以用来同步对系统资源的访问。

注意:虽然说的是队列,但不是 fifo,没有 fifo 的特性



1. 等待队列: -- wait queue在 Linux 驱动程序中,可以使用等待队列(wait queue)来实现阻塞进程的唤醒。它以队列为基础数据结构,与进程调度机制紧密结合,能够用于实现内核中的异步事件通知机制。等待队列可以用来同步对系统资源的访问,信号量在内核中依赖等待队列来实现。



定义“等待队列头”

wait_queue_head_t my_queue;



初始化“等待队列头”

init_waitqueue_head(&my_queue);



而下面的 DECLARE_WAIT_QUEUE_HEAD()宏可以作为定义并初始化等待队列头的“快捷方式”。

DECLARE_WAIT_QUEUE_HEAD (name)



定义等待队列

DECLARE_WAITQUEUE(name, tsk)

该宏用于定义并初始化一个名为 name 的等待队列。



添加/移除等待队列

void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);

void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);

add_wait_queue()用于将等待队列 wait 添加到等待队列头 q 指向的等待队列链表中,而remove_wait_queue()用于将等待队列 wait 从附属的等待队列头 q 指向的等待队列链表中移除。



等待事件

wait_event(wait_queue_head_t queue, condition) --> 深睡,不可以被信号打断

wait_event_interruptible(wait_queue_head_t queue, condition) --> 浅睡,可以被信号打断

wait_event_timeout(wait_queue_head_t queue, condition, timeout)

wait_event_interruptible_timeout(wait_queue_head_t queue, condition, timeout)

queue,作为等待队列头的等待队列被唤醒

condition,条件,满足 唤醒,否则 阻塞

timeout,阻塞等待的超时时间,单位是 jiffy,等待时间 timeout 后,无论条件满足不满足,都返回



唤醒队列

void wake_up(wait_queue_head_t *queue);

void wake_up_interruptible(wait_queue_head_t *queue);

唤醒时会判断 condition



①wake_up() -- wait_event() / wait_event_timeout()

②wake_up_interruptible() -- wait_event_interruptible() / wait_event_interruptible_timeout()



①可以唤醒处于 TASK_INTERRUPTIBLE 和 TASK_UNINTERRUPTIBLE 的进程

②可以唤醒处于 TASK_INTERRUPTIBLE 的进程



在等待队列上睡眠:

sleep_on(wait_queue_head_t *q);

interruptible_sleep_on(wait_queue_head_t *q);

sleep_on 将目前进程的状态置成 TASK_UNINTERRUPTIBLE,并定义一个等待队列,之后把它附属到等待队列头 q,直到资源可获得,q 引导的等待队列被唤醒。

wake_up_interruptible将目前进程的状态置成 TASK_ INTERRUPTIBLE,并定义一个等待队列,之后把它附属到等待队列头q,直到资源可获得,q引导的等待队列被唤醒或者进程收到信号。

sleep_on()函数应该与 wake_up()成对使用,interruptible_sleep_on()应该wake_up_interruptible()

成对使用。



注意:

在许多设备驱动中,并不调用 sleep_on()或 interruptible_sleep_on(),而是亲自进行进程的状态改变和切换



2. 例子为了让 驱动支持 阻塞和非阻塞,需要在驱动中使用等待队列:



waitqueue.c

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

430

主题

436

帖子

0

粉丝