linux中非阻塞IO的个人理解总结

非阻塞和阻塞最基本区别是:
在条件没达到设定情况下:
①阻塞会在驱动中让线程或者进程一直等待(陷入睡眠,从running队列中去掉(驱动层实现)),就导致应用层就会有限制没有完全自由度.
②非阻塞会在驱动中直接返回一个未达到条件的状态但并没有将线程或者进程陷入睡眠,应用层就会比 ‘阻塞’ 对这个设备有更多的自由度.
poll函数参数:

#include <poll.h>
struct pollfd {
   
               int   fd;         /* file descriptor */
               short events;     /* requested events */
               short revents;    /* returned events */
};
// An highlighted block
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

因为基本上网上例子中并没有描述过关于监听多个文件的,并且
很多人对第二个参数nfds应该很模糊.所以下面开始主要对非阻塞的操作进行记录:
①应用会打开 “/dev/read_key_vaule” 设备,并且创建装有5个struct pollfd类型的元素数组monitor_fd[5],使用monitor_fd[4]对该文件进行监视是否可以读取数据的事件POLLIN(POLLIN说是输入事件,其实具体代表什么事件完全看驱动到达某一个事件我们返回应用什么就是什么(具体应用查看struct pollfd类型的监听结构体成员revents即可)。只是为了和linux统一,方便看,没有什么特别意义).
在这里插入图片描述应用调用poll函数(第二个参数为什么是5会在后面详细讲解),当应用调用poll函数,也就会调用驱动层的poll函数.
在这里插入图片描述下图为驱动层设备文件操作集中的poll函数,主要红框内使用原子数据进行判断是否可以操作的条件,满足就会将事件返回给应用,否则就立即返回-EBUSY。这里poll_wait比较关键,是将该进程放到等待队列中等待事件是否满足,但是这个调用不会让进程睡眠,不会让进程睡眠,不会让进程睡眠,重要事情说三遍!!!.
在这里插入图片描述那么这个原子数据总得有个地方将他改变吧?不然这个驱动没啊,是吧。
红框1中如果应用层写入该设备文件字符’E’就会将这个原子数据改变,使得poll的监视得到满足匹配。那么如果应用层写入不是’E’那么就不会让poll的监听有效.(这里使用另一个app_write向该设备文件写入’E’).
在这里插入图片描述以下是app_write写入部分代码.
在这里插入图片描述
当执行上面代码,写入设备’E’后,会打印atomic become active.
在这里插入图片描述
所以驱动中poll就会执行

mask = POLLIN | POLLRDNORM;
...
return mask;

并且在应用层也可以读数据得到驱动中read函数返回给应用的0x99.如下图部分代码和打印结果.
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
以上为正常使用非阻塞一般流程,select基本和poll差不多,除了应用层,驱动层都是poll回调函数,这里就不说了.

下面说一下应用层poll的第二个参数,为什么笔者这里传入5而不是其他的值?
先看现象:
第二个参数传入0~4均为同一个现象,所以这里使用1来作为一个例子描述.
在这里插入图片描述当打开文件(中间的timeout为打开设备后,没有及时写入数据,导致打印超时信息),在写入设备后仍然提示超时,说明改监视结构体没有监视到预期状态。
在这里插入图片描述
其他代码均没有改变,只更改了第二个参数为5,结果就不一样。
在这里插入图片描述

在这里插入图片描述为什么呢?
因为要监听是数组的最后一个元素,是监视结构体起始地址偏移五个位移,所以如man手册所说

The caller should specify the number of items in the fds array in nfds.

那么这里如果这么写仍然是不对。

// test
ready = poll(monitor_fd[4],5,5000);

这里如果这么写就对了,所以结论就出来了。

// test
ready = poll(monitor_fd[4],1,5000);

另外一般会监听多个设备,所以监听几个设备就要调用几次poll函数

// test
ready4 = poll(monitor_fd[4],1,5000);
ready2 = poll(monitor_fd[2],1,5000);
ready0 = poll(monitor_fd[0],1,5000);

poll参数最后一个是毫秒单位,这里类型int,和select还有点区别,调用时候需要注意.
而且应用在调用poll后会等待第三个参数时间,时间到了才会返回一个值,应用进行处理。并不是立刻返回描绘根据我们应用设定的超时时间。
全部代码如下:

// driver for noblock_io
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/jiffies.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#define KEY_NAME "read_key_vaule"
static int _key_open(struct inode * pinode<
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值