一. 简介
阻塞与非阻塞IO是Linux驱动开发中很常见的两种设备访问模式,在编写驱动的时候,一定要考虑到阻塞和非阻塞。
本文来学习一下,什么是 Linux下的阻塞与非阻塞IO访问。
二. Linux阻塞与非阻塞IO
这里的 “IO” 并不是我们学习 STM32 或者其他单片机的时候所说的“GPIO” (也就是引脚)。
这里的 "IO"指的是Input / Output,也就是输入 / 输出,是应用程序对驱动设备的输入操作 / 输出操作。
1. 阻塞IO
当应用程序对设备驱动进行操作的时候,如果不能获取到设备资源,那么阻塞式 IO 就会将应用程序对应的线程挂起,直到设备资源可以获取为止。
阻塞式 IO 如下图所示:
可以看出,阻塞访问IO:应用程序调用 read 函数从设备中读取数据,当设备不可用或数据未准备好时,线程就会进入到休眠态。等设备可用时,线程就会从休眠态唤醒,然后从设备中读取数据返回给应用程序。
2. 非阻塞IO
对于非阻塞 IO,应用程序对应的线程不会挂起,它要么一直轮询等待,直到设备资源可以使用,要么就直接放弃。
非阻塞 IO 如下图所示:
可以看出,应用程序使用非阻塞访问方式从设备读取数据,当设备不可用或数据未准备好时,会立即向应用程序返回一个错误码,表示数据读取失败。应用程序会再次重新读取数据,这样一直往复循环,直到数据读取成功。
三. 阻塞与非阻塞IO访问举例
下面通过打开文件举例说明 阻塞式访问与非阻塞访问。
1. 阻塞式访问打开文件
应用程序可以使用如下所示示例代码来实现阻塞IO访问:
int fd;
int data = 0;
fd = open("/dev/xxx_dev", O_RDWR); /* 阻塞方式打开 */
ret = read(fd, &data, sizeof(data)); /* 读取数据 */
可以看出,对于设备驱动文件的默认读取方式就是阻塞式的,所以,我们前面所有的例程测试 APP 都是采用阻塞 IO。
2. 非阻塞式访问打开文件
如果应用程序要采用非阻塞的方式来访问驱动设备文件,可以使用如下所示代码:
int fd;
int data = 0;
fd = open("/dev/xxx_dev", O_RDWR | O_NONBLOCK); /* 非阻塞方式打开 */
ret = read(fd, &data, sizeof(data)); /* 读取数据 */
可以看出:
第 4行 使用 open 函数打开“/dev/xxx_dev”设备文件的时候添加了参数数“O_NONBLOCK”, 表示以非阻塞方式打开设备,这样从设备中读取数据的时候就是非阻塞方式的了。