阻塞和非阻塞型IO

上传人:平*** 文档编号:34251235 上传时间:2018-02-22 格式:PPTX 页数:31 大小:1.25MB
返回 下载 相关 举报
阻塞和非阻塞型IO_第1页
第1页 / 共31页
阻塞和非阻塞型IO_第2页
第2页 / 共31页
阻塞和非阻塞型IO_第3页
第3页 / 共31页
阻塞和非阻塞型IO_第4页
第4页 / 共31页
阻塞和非阻塞型IO_第5页
第5页 / 共31页
点击查看更多>>
资源描述

《阻塞和非阻塞型IO》由会员分享,可在线阅读,更多相关《阻塞和非阻塞型IO(31页珍藏版)》请在金锄头文库上搜索。

1、上章回 顾从并发的需要,引起的竞争状态,到解决竞争状态的方法机制 :禁 止中断信号 量自 旋锁Completion原子操 作 阻塞和非阻塞型 I/O第 4章本章目标掌握进程睡眠和唤醒的方法 掌握阻塞型 I/O的实现方法 掌握 poll/select系统调用的实现方法 本章结构阻塞型 I/O 阻塞和非阻塞型 I/O异步通知 非阻塞 I/O 非阻塞 I/Opoll/select进程休眠和唤醒方法 阻塞型 I/O实例 4-1 阻塞型 I/O当 用户程 序 调 用 read函数时,驱动程序的 read并没有准备好数据,怎么办?当用户程序调用 write时,驱动程序的 write的缓冲区已满,此时怎么办

2、?1.用户程序不会管理这些问题。2.驱动程序默认情况下,阻塞该进程。 将其置入休眠状态直到 请求可 继 续3. 直接返回,这是非阻塞 IO4-1-1进程休眠和唤醒 方法休眠的意义?从调度器的运行队列 某个等待队列等 到某个事件发生,在从等待队列返回到运行队列。如何将进程安全的进入休眠状态?不能在原子上下 文进行休眠 :休 眠时,对外界一无所知,进程必须重新检测等待条件进程只有确保会被其他进程唤醒,才能进入休眠需要等待队列来管理和维护 这些信 息 :等待队列就是一个进程链表,其中包含了等待某个特定事件的所有进程4-1-1进程休眠和唤醒方法等待队列 的作用实现阻塞进程的唤醒实现内核中的异步事件通知

3、机 制队列的数据结构系统的调度机制同步系统资源的访问Semaphore可以用 wait queue来实现4-1-1进程休眠和唤醒方法等待队列通过 ”等待队列头 ”来管理Struct wait_queue_head_t DECLARE_WAIT_QUEUE_HEAD(name);wait_queue_head_t xxx_queue;init_waitqueue_head(&xxx_queue);4-1-1进程休眠和唤醒方法等待事件在休眠的同时,也检查进程等待的条件休眠函数wait_event(queue, condition);wait_event_interruptible(queue, c

4、ondition);wait_event_timeout(queue, condition, timeout);wait_event_interruptible_timeout(queue, condition, timeout);休眠前后都要对该表达式求值;在条件为真之前,进程会保持休眠等待队列 头,通过 ”值传递 ”4-1-1进程休眠和唤醒方法唤醒函数wake_up(wait_queue_head_t *queue);wake_up_interruptible(wait_queue_head_t *queue);约定的做法是成对使用wake_up_nr(wait_queue_head_t

5、*queue, int nr);wake_up_interruptible_nr(wait_queue_head_t *queue, int nr);唤醒 nr各独占等待进程,而不是一个,当 nr=0时,唤醒所有的独占等待进程。wake_up_all(wait_queue_head_t *queue);wake_up_interruptible_all(wait_queue_head_t *queue);wake_up_interruptible_sync(wait_queue_head_t *queue);4-1-1进程休眠和唤醒方法static DECLARE_WAIT_QUEUE_HEA

6、D(wq);static int flag = 0;ssize_t sleepy_read(struct file *filp, char _user *buf,size_t count,loff t *pos)printk(KERN_DEBUG “process %i (%s) going to sleepn”,current-pid, current-comm);wait_event_interruptible(wq, flag != 0);flag = 0;printk(KERN_DEBUG “awoken %i (%s)n”, current-pid, current-comm);re

7、turn 0;定义并初始化wait_queue_head_t 打印出是哪个进程调用驱动程序。在调用前后都要检查 condition,如果满足条件,就不再休眠,否则进入休眠状态4-1-1进程休眠和唤醒方法ssize_t sleepy_write(struct file *filp, const char _user *buf, size_t count,loff_t *pos)printk(KERN_DEBUG “process %i (%s) awakening the readersn” ,current-pid, current-comm);flag = 1;wake_up_interru

8、ptible(&wq);return count;察看那个进程调用 驱动的 write函数唤醒休眠在 wq队列上的所有的进程。4-1-1进程休眠和唤醒方法上面实例中存在一个概率很小的竟态条件A,B 进程都等在 wq的队列上C进程调用 wait_event_interruptibleA进程被唤醒,检查条件 flag !=0 成立此时,调度到 B进程B进程也检查到 flag != 0成立,这样,一个事件唤醒了 两 个进程,可能产生竞 态可以用原子操作防止这种情况 4-1-1进程休眠和唤醒方法设置进程休眠的内部细节分配并初始化一个 wait_queue_t结构包含休眠进程的信息,以及期望被唤醒的相关

9、细节设置进程的状态,将其标记为休眠状态TASK_INTERRUTIBLETASK_UNINTERRUPTIBLE让出处理器void set_current_state(int new_state);current-state=TASK_INTERRUPTIBLE;if(!condition)schedule();4-1-1进程休眠和唤醒方法手工休眠早期版本的方法读者可以自行了解唤醒等待队列可能发生的情况当调用 wake_up时,所有等待在该队列上的进程都被唤醒,并进入可运行状态如果只有一个进程可获得资源,此时,其他的进程又将再次进入休眠如果数量很大,被称为 ”疯狂售群 ”4-1-1进程休眠和唤

10、醒方法独占等待与普通休眠的不同等待队列入口设置了 WQ_FLAG_EXCLUSIVE标志时,则会被添加到等待队列的尾部。而没有这个标志的入口会被添加到头部。在某个等待队列上调用 wake_up时,它会在唤醒第一个具有WQ_FLAG_EXCLUSIVE标志的进程之后停止唤醒其他进程。使进程进入独占等待函数:void prepare_to_wait_exclusive(wait_queue_head_t *queuewait_queue_t *wait, int state);使用 wait_event的变种都无法使用独占等待4-1-1进程休眠和唤醒方法其他休眠调用void sleep_on(wa

11、it_queue_head_t *queue);void interruptible_sleep_on(wait_queue_head_t *queue);4-1-2阻塞型 IO实例struct xxx_pipewait_queue_head_t inq, outq; /*读取和写入队列 */char *buffer, *end; /*缓冲区的起始和结尾 */int buffersize; /*用于指针计算 */char *rp, *wp; /*读取和写入的位置 */int nreaders, nwriters; /*用于读写打开的数量 */struct fasync_struct *asyn

12、c_queue; /*异步读取者 */struct semaphore sem; /*互斥信号量 */struct cdev cdev; /*字符设备结构 */;4-1-2阻塞型 IO实例static ssize_t xxx_read(struct file *filp, char _user *buf,size_t count,loff_t *f_pos)struct xxx_pipe *dev=filp-private_data;if(down_interruptible(&dev-sem)return -ERESTARTSYS;while(dev-rp = dev-wp) /*无数据可读

13、取 */up(&dev-sem); /*释放锁 */if(filp-f-flags O_NONBLOCK)return -EAGAIN;if(wait_event_interruptible(dev-inq, (dev-rp!=dev-wp)return -ERESTARTSYS; /*信号,通知 fs层做相应处理 */*否则循环,但首先获取锁 */if(down_interruptible(&dev-sem)return -ERESTARTSYS;4-1-2阻塞型 IO实例/*数据已就绪,返回 */if(dev-wp dev-rp)count=min(count, (size_t)(dev-

14、wp - dev-rp);else/*写入指针回卷,返回数据直到 dev-end*/count=min(count, (size_t)(dev-end dev-rp);if(copy_to_user(buf, dev-rp, count)up(&dev-sem);return -EFAULT;dev-rp += count:if(dev-rp = dev-end)dev-rp = dev-buffer; /*回卷 */up(&dev-sem);/*最后,唤醒所有写入者并返回 */wake_up_interruptible(&dev-outq);return count; 阶段总结 介绍了阻塞型

15、 I/O的实现方法 介绍了进程休眠和唤醒的方法,重点介绍了wait_event和 wake_up4-2 非阻塞 I/O调用进程显式的指明不想阻塞设置 filp-f_flag |= O_NONBLOCKint fd;char buf;fd = open(“/dev/ttyS1”,O_RDWR | O_NONBLOCK);while(read(fd, /*串口上无输入也返回,所以要循环尝试读取串口 */printf(“%cn”,buf);4-2-1 poll和 selectPoll、 select、 epoll 都允许进程决定是否可以对一个或多个打开的文件做非阻塞的读取或写入这些调用也会阻塞进程,直到给定的文件描述符集合中的任何一个可读取或写入常常用于那些要使用多个输入或输出流而又不会阻塞于其中任何一个流的应用程序中4-2-1 poll和 select都是调用驱动程序的 poll来实现的在一个或多个可指示 poll状态

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号