这篇文章我们来了解下Linux设备驱动中阻塞和非阻塞。

阻塞:阻塞是指执行设备操作时,如果不能获得设备资源,则挂起进程,是进程进入休眠模式,直到设备资源可以获取。

非阻塞:非阻塞是在不能获取设备资源时,要么放弃获取,要么一直不停的查询,直到可以获取资源。

这两种操作能够为为应用程序提供这样的能力:

(1)当应用程序对设备资源进行read(), write()操作时,如果设备资源不能获取,用户以阻塞的方式进行访问,则驱动程序在设备驱动的xxx_read(), xxx_write()等操作中将进程阻塞直到资源可以获取,之后应用程序的read(), write()的调用才能返回。

(2)如果应用程序进行上述操作时,用户以非阻塞的方式进行访问时,设备资源不能获取时,设备驱动的xxx_read(),xxx_write()等操作立即返回,应用程序的read(),write()等系统调用立即返回,应用程序受到-EAGAIN 返回值。

下面这幅图是Linux开发详解中的图,可以加深理解。

使用例子:

fd = open("/dev/ttyS1", O_RDWR);  阻塞的形式;

fd = open("/dev/ttyS1", O_RDWR| O_NONBLOCK);  非阻塞的形式;

那么在Linux驱动程序中,是如何实现阻塞进程的唤醒呢?下面有几种方法使用:

(1)等待队列 ( wait queue),等待队列是以队列为基础数据结构实现的。

1)使用方法:

首先定义等待队列的头部: wait_queue_head_t  my_queue;

初始化等待队列的头部:init_waitqueue_head(&my_queue); DECLARE_WAIT_QUEUE_HEAD() 宏是定义并初始化等待队列头部的快捷方式。

定义等待队列元素:DECLARE_WAITQUEUE(name, tsk) ,该宏用于定义并初始化一个名为name的等待队列元素。

添加/移除等待队列: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);

add_wait_queue()用于将等待队列元素wait添加到等待队列头部q指向的双向链表中。remove 函数执行移除操作。

等待事件:

wait_event(queue, condition); 等待第一个参数queue作为等待队列头部的队列被唤醒,而且第二个参数condition必须满足,否则继续阻塞。
     wait_event_interruptible(queue, condition); 可被信号中断
     wait_event_timeout(queue, condition, timeout)   加了等待超时时间,超时时间到不论condition是否满足均返回。
    wait_event_interruptible_timeout(queue, condition, timeout)

唤醒队列:void wake_up(wait_queue_head_t *queue);
                   void wake_up_interruptible(wait_queue_head_t *queue);

唤醒以queue作为等待队列头部的队列中所有的进程。

在等待队列上睡眠:

sleep_on(wait_queue_head_t *q );  将目前进程的状态置成TASK_UNINTERRUPTIBLE,并定义一个等待队列元素,之后把它挂到等待队列头部q指向的双向链表,直到资源可获得,q队列指向链接的进程被唤醒。
         interruptible_sleep_on(wait_queue_head_t *q );目前进程的状态置成TASK_INTERRUPTIBLE,并定义一个等待队列
元素,之后把它附属到q指向的队列,直到资源可获得(q指引的等待队列被唤醒)或者进程收到信号。

有了前面的基本概念知识后,我们通过这段书上的代码来理解:

static ssize_t xxx_write(struct file *file, const char *buffer, size_t count,loff_t *ppos)
{DECLARE_WAITQUEUE(wait, current); /* 定义等待队列元素 */add_wait_queue(&xxx_wait, &wait); /* 添加元素到等待队列 *//* 等待设备缓冲区可写 */do {avail = device_writable(...);if (avail < 0) {if (file->f_flags &O_NONBLOCK) { /* 非阻塞 */ret = -EAGAIN;goto out;}__set_current_state(TASK_INTERRUPTIBLE); /* 改变进程状态 */schedule(); /* 调度其他进程执行 */if (signal_pending(current)) { /* 如果是因为信号唤醒 */ret = -ERESTARTSYS;goto out;}} while (avail < 0);/* 写设备缓冲区 */device_write(...);out:remove_wait_queue(&xxx_wait, &wait); /* 将元素移出 xxx_wait 指引的队列 */set_current_state(TASK_RUNNING); /* 设置进程状态为 TASK_RUNNING */return ret;
}

1)如果是非阻塞访问(O_NONBLOCK被设置),设备忙时,直接返回“-EAGAIN”。
2)对于阻塞访问,会调用__set_current_state(TASK_INTERRUPTIBLE)进行进程状态切换并显示通过“schedule()”调度其他进程执行。
3)醒来的时候要注意,由于调度出去的时候,进程状态是TASK_INTERRUPTIBLE,即浅度睡眠,所以唤醒它的有可能是信号,因此,我们首先通过signal_pending(current)了解是不是信号唤醒的,如果是,立即返回“-ERESTARTSYS”。
非阻塞的实现有: select() 和poll() 。

Linux设备驱动中的阻塞和非阻塞IO相关推荐

  1. linux 设备驱动阻塞,深入浅出:Linux设备驱动中的阻塞和非阻塞I/O

    今天写的是Linux设备驱动中的阻塞和非阻塞I/0,何谓阻塞与非阻塞I/O?简单来说就是对I/O操作的两种不同的方式,驱动程序可以灵活的支持用户空间对设备的这两种访问方式. 一.基本概念: 阻塞操作 ...

  2. linux write引起进程挂起,Linux设备驱动中的阻塞与非阻塞总结

    Linux设备驱动中的阻塞与非阻塞总结 阻塞操作是指,在执行设备操作时,若不能获得资源,则进程挂起直到满足可操作的条件再进行操作. 非阻塞操作的进程在不能进行设备操作时,并不挂起.被挂起的进程进入sl ...

  3. Linux设备驱动中的并发控制总结

    并发(concurrency)指的是多个执行单元同时.并行被执行.而并发的执行单元对共享资源(硬件资源和软件上的全局.静态变量)的访问则容易导致竞态(race conditions).   SMP是一 ...

  4. linux 两个驱动 竞态,第7章 Linux设备驱动中的并发控制之一(并发与竞态)

    本章导读 Linux设备驱动中必须解决的一个问题是多个进程对共享资源的并发访问,并发的访问会导致竞态(竞争状态). Linux提供了多种解决竞态问题的方式,这些方式适合不同的应用场景. 7.1讲解了并 ...

  5. Linux设备驱动开发详解:第7章 Linux设备驱动中的并发控制

    7.1并发与竞态 (1).竞态的发生场景:CPU0的进程与CPU1的进程之间.CPU0的中断与CPU1的进程之间.CPU0的中断与CPU1的中断之间: (2).解决竞态问题的途径是保证对共享资源的互斥 ...

  6. Linux 设备驱动中的 I/O模型(一)—— 阻塞和非阻塞I/O

    在前面学习网络编程时,曾经学过I/O模型 Linux 系统应用编程--网络编程(I/O模型),下面学习一下I/O模型在设备驱动中的应用. 回顾一下在Unix/Linux下共有五种I/O模型,分别是: ...

  7. Linux设备驱动中的阻塞与非阻塞I/O

    阻塞和非阻塞I/O是设备访问的两种不同模式,驱动程序可以灵活的支持用户空间对设备的这两种访问方式 本例子讲述了这两者的区别 并实现I/O的等待队列机制, 并进行了用户空间的验证 基本概念: 1> ...

  8. Linux 设备驱动中的阻塞与非阻塞 I/O

    阻塞操作是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作.被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足.而非阻塞操作的进程在不能进行设备操作时 ...

  9. linux设备驱动中的阻塞与非阻塞(一)

    这两天在搞linux驱动的阻塞和非阻塞,困扰了两天,看了不少博客,有了点自己的想法,也不知是否对错,但还是写写吧,让各位大神给我指点指点.       首先说说什么是阻塞和非阻塞的概念:阻塞操作就是指 ...

最新文章

  1. ubuntu安装ssh,安装失败
  2. 小学计算机课总目标,小学信息技术课堂教学目标的确定与实现
  3. CSS导航栏实例详解
  4. 90后CV男神Workshop | 祥雨带你畅聊Model设计新视角
  5. 2016年印度公有云服务市场将达13亿美元
  6. Eclipse中tomcat的简单配置
  7. python实现xmind_Python xmind库(生成框架图)
  8. python3 循环写入一对多键值对_Python 3.9 正式版要来了,会有哪些新特性?
  9. Python简记--函数
  10. 牵引力教育推荐最先进的5大敏捷PHP开发框架
  11. 浅析基本事实表的ETL处理
  12. python 绘制图表生成svg文件_python用Pygal如何生成漂亮的SVG图像详解
  13. @autowired注解注入为null_Spring @Autowired 注解自动注入流程是怎么样?
  14. STM32 实现光敏传感器
  15. 【微信页面】移动端微信页面禁止字体放大
  16. visio2019怎么对图片加箭头标注,Visio设置图片作为背景
  17. 华为云计算IE面试笔记-云磁盘和普通磁盘的区别。
  18. pytorch求STFT
  19. 200左右哪款蓝牙耳机值得入手?双11小白新手避雷高性能蓝牙耳机
  20. python从文件中读取数据_【Python】从文件中读取数据

热门文章

  1. 学生HTML个人网页作业作品 ~ 科技大学官网 网页设计成品~ 学生网页设计作业源码
  2. Windows Mobile下GPS管理软件NavsGo之GPS侦测功能的开发
  3. STM32(7):定时器之PWM
  4. 对 GPIOB_ODR|=(1<<10) GPIOB_ODR=~(1<<10)的理解
  5. Unity3D 双面渲染Shader实现
  6. js filter函数
  7. 联邦学习-论文阅读-NDSS-FLTrust: Byzantine-robust Federated Learning via Trust Bootstrapping
  8. php单双引号拼接,js字符串拼接中关于单引号和双引号的那些事
  9. 如何做好一个垂直搜索引擎
  10. IP地址 分类 ?网络位主机位? 子网掩码?网段?域名?DNS?