Linux阻塞和非阻塞I/O实验 📅 2026/8/15 11:09:34 1.IO与阻塞io与非阻塞IO概念个人认为非阻塞IO优势大为什么非阻塞IO的CPU利用率高因为阻塞IO进入阻塞态需要时间。2.应用程序实现非阻塞访问1实现打开文件并且设置标志位为“O_RDWR”可读可写使用fcntl去修改它的标志位先fcntl文件描述符F_GETFL获取fl0获取标志位然后fcntl文件描述符F_SETFL设置fl非阻塞。2将O_NOBLOCK删了就是阻塞访问所以之前写的应用程序都是阻塞访问的。3.等待队列3.1等待队列相关API(1)(2)(3)(4)tsk一般给current(5)添加与移除等待队列项6唤醒参数x是等待队列头使用该函数后队列中的全部等待队列中的所有进程7等待条件condition完成条件即可被唤醒4.轮询用于应用程序4.1 应用程序中轮询函数1select函数不关注的写NULL。select函数最多可监听1024个文件。2poll函数无监视数量限制。3epoll函数仅linux平台可使用很牛可以使用在网络文件中但是简单的文件select和poll即可。4.2 驱动中poll在文件结构体中添加poll对应相关函数当应用代码中使用select和poll对应驱动程序中使用以上函数。5.阻塞IO实验基于按键中断实验代码keyirq.ckey_read函数在这个函数中我们会判断按键是否有按下或松开动作发生 如果没有则调用 wait_event_interruptible把它加入等待队列当中进行阻塞如果等待队列被唤醒并且条件“KEY_KEEP ! atomic_read(status)”成立则会解除阻塞继续下面的操作也就是读取按键状态数据将其发送给应用程序因为采用了 wait_event_interruptible函数因此进入休眠态的进程可以被信号打断在该函数中我们读取 status原子变量必须要使用atomic_read 函数进行操作。static ssize_t key_read(struct file *filp,char __user *buf, size_t cnt,loff_t *offt) { int ret; /* 加入等待队列当有按键按下或松开动作发生时才会被唤醒 */ ret wait_event_interruptible(key.r_wait,KEY_KEEP ! atomic_read(status)); if(ret) return ret; /* 将按键状态信息发送给应用程序 */ ret copy_to_user(buf,status,sizeof(int)); /* 状态重置 */ atomic_set(status, KEY_KEEP); return ret; }6.非阻塞IO实验基于阻塞IO实验blockIio.c第 29行使用include将内核源码目录include/linux/poll.h头文件包含进来。第 76~98行key_read函数中判断是否为非阻塞式读取访问如果是的话就判断按键状态是否有效也就是判断是否产生了按下或松开这样的动作如果没有的话就返回-EAGAIN。第 106~116行key_poll函数就是file_operations驱动操作集中的poll函数当应用程序调用select或者poll函数的时候key_poll函数就会执行。第110行调用poll_wait函数将等待队列头添加到poll_table中第112~113行判断按键是否有效如果按键有效的话就向应用程序返回POLLIN这个事件表示有数据可以读取。第 252行设置file_operations的poll成员变量为key_poll。static ssize_t key_read(struct file *filp,char __user *buf, size_t cnt,loff_t *offt) { int ret; //兼容阻塞与非阻塞先判断是不是非阻塞访问如果不是就使用等待队列 if(filp-f_flags O_NONBLOCK){ //非阻塞方式访问 if(KEY_KEEP atomic_read(status)) return -EAGAIN; }else{ // 阻塞方式访问 /* 加入等待队列当有按键按下或松开动作发生时才会被唤醒 */ ret wait_event_interruptible(key.r_wait,KEY_KEEP ! atomic_read(status)); if(ret) return ret; } /* 将按键状态信息发送给应用程序 */ ret copy_to_user(buf,status,sizeof(int)); /* 状态重置 */ atomic_set(status, KEY_KEEP); return ret; } /* * description : poll函数用于处理非阻塞访问 * param - filp : 要打开的设备文件(文件描述符) * param - wait : 等待列表(poll_table) * return : 设备或者资源状态 */ static unsigned int key_poll(struct file *filp, struct poll_table_struct *wait) { unsigned int mask 0; poll_wait(filp, key.r_wait, wait); //*核心将进程放入等待队列直到它检测到按键数据发生变化的时候才会被唤醒 if(KEY_KEEP ! atomic_read(status)) // 按键按下或松开动作发生 mask POLLIN | POLLRDNORM; // 返回PLLIN return mask; }