lv14 IO模型:阻塞和非阻塞 7

1 五种IO模型------读写外设数据的方式

阻塞: 不能操作就睡觉

非阻塞:不能操作就返回错误(通过轮询即才能实现阻塞的情况 )

多路复用:委托中介监控

信号驱动:让内核如果能操作时发信号,在信号处理函数中操作

异步IO:向内核注册操作请求,内核完成操作后发通知信号

2 阻塞与非阻塞

应用层:

open时由O_NONBLOCK指示read、write时是否阻塞

open以后可以由fcntl函数来改变是否阻塞:

flags = fcntl(fd,F_GETFL,0);  //获取当前设备中标志位
flags |= O_NONBLOCK;          //增加不阻塞标志位
fcntl(fd, F_SETFL, flags);    //设置当前标志位到设备中

驱动层:通过等待队列

wait_queue_head_t //等待队列头数据类型
​
init_waitqueue_head(wait_queue_head_t *pwq) //初始化等待队列头wait_event_interruptible(wq,condition)
/*
功能:条件不成立则让任务进入浅度睡眠,直到条件成立醒来wq:等待队列头condition:C语言表达式
返回:正常唤醒返回0,信号唤醒返回非0(此时读写操作函数应返回-ERESTARTSYS)
*/wait_event(wq,condition) //深度睡眠
​
wake_up_interruptible(wait_queue_head_t *pwq)wake_up(wait_queue_head_t *pwq)/*
1. 读、写用不同的等待队列头rq、wq
2. 无数据可读、可写时调用wait_event_interruptible(rq、wq,条件)
3. 写入数据成功时唤醒rq,读出数据成功唤醒wq
*/
​

2.1 示例

mychar.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>#include "mychar.h"#define BUF_LEN 100#define MYCHAR_DEV_CNT 3int major = 11;
int minor = 0;
int mychar_num  = MYCHAR_DEV_CNT;//新建结构体类型
struct mychar_dev
{struct cdev mydev;char mydef_buf[BUF_LEN];  //相当于结构体的私有变量int curlen;          //相当于结构体的私有变量wait_queue_head_t rq; //等待读队列wait_queue_head_t wq; //等待写队列};struct mychar_dev gmydev;int mychar_open(struct inode *pnode, struct file *pfile)
{//利用private_data私有变量来指向全局变量结构体地址pfile->private_data = (void*)(container_of(pnode->i_cdev,struct mychar_dev,mydev));printk("mychar_open is called\n");return 0;
}int mychar_close(struct inode *pnode, struct file *pfile)
{printk("mychar_close is called\n");return 0;
}ssize_t mychar_read(struct file *filp, char __user *pbuf, size_t count, loff_t *ppos)
{int ret = 0;int size = 0;//获取全家变量结构体地址struct mychar_dev *pmydev = (struct mychar_dev *)filp->private_data;if(pmydev->curlen <= 0){if(filp->f_flags & O_NONBLOCK){//非阻塞printk("O_NONBLOCK No Data Read\n");return -1;}else{//阻塞ret = wait_event_interruptible(pmydev->rq,pmydev->curlen > 0);if(ret){printk("Wake up by signal\n");return -ERESTARTSYS;}}}if(count > pmydev->curlen){size = pmydev->curlen;}else{size = count;}//将内核空间中的数据复制到用户空间ret = copy_to_user(pbuf,pmydev->mydef_buf,size);if(ret){printk("copy_to_user failed\n");return -1;}//读完之后把后面的内容再拷贝过来,同时更新curlenmemcpy(pmydev->mydef_buf,pmydev->mydef_buf+size,pmydev->curlen - size);pmydev->curlen = pmydev->curlen - size;wake_up_interruptible(&pmydev->wq);return size;}ssize_t mychar_write (struct file *filp, const char __user *pbuf, size_t count, loff_t *ppos)
{int size = 0;int ret  = 0;//获取全家变量结构体地址struct mychar_dev *pmydev = (struct mychar_dev *)filp->private_data;if(pmydev->curlen >= BUF_LEN){if(filp->f_flags & O_NONBLOCK){printk("O_NONBLOCK Can not write data\n");return -1;}else{ret = wait_event_interruptible(pmydev->wq,pmydev->curlen < BUF_LEN);if(ret){printk("wake up by signal\n");return -ERESTARTSYS;}}}if(count > BUF_LEN - pmydev->curlen){size = BUF_LEN - pmydev->curlen;}else{size = count;}//将用户空间中的数据复制到内核空间中ret = copy_from_user(pmydev->mydef_buf + pmydev->curlen, pbuf, size);if(ret){printk("copy_from_user failed\n");return -1;}//更新curlenpmydev->curlen = pmydev->curlen + size;wake_up_interruptible(&pmydev->rq);return size;
}long mychar_ioctl(struct file *filp, unsigned int cmd,unsigned long arg)
{int __user *pret = (int *)arg;int maxlen = BUF_LEN;int ret = 0;struct mychar_dev *pmydev = (struct mychar_dev *)filp->private_data;switch(cmd){case MYCHAR_IOCTL_GET_MAXLEN:ret = copy_to_user(pret,&maxlen,sizeof(int));if(ret){printk("copy_to_user MAXLEN failed\n");return -1;}break;case MYCHAR_IOCTL_GET_CURLEN:ret = copy_to_user(pret,&pmydev->curlen,sizeof(int));if(ret){printk("copy_to_user CURLEN failed\n");return -1;}break;default:printk("The cmd is unknow\n");return -1;}return 0;
}//结构体初始化:部分变量赋值初始化
struct file_operations myops = {.owner = THIS_MODULE,.open = mychar_open,.release = mychar_close,.read = mychar_read,.write = mychar_write,.unlocked_ioctl = mychar_ioctl
};int mychar_init(void)
{int ret = 0;dev_t devno = MKDEV(major, minor);/* 申请设备号 */ret = register_chrdev_region(devno, mychar_num, "mychar");if (ret) {ret = alloc_chrdev_region(&devno, minor, mychar_num, "mychar");if (ret) {printk("get devno failed\n");return -1;}major = MAJOR(devno); // 容易遗漏,注意}/* 给struct cdev对象指定操作函数集 */cdev_init(&gmydev.mydev, &myops);/* 将 struct cdev对象添加到内核对应的数据结构里 */gmydev.mydev.owner = THIS_MODULE;cdev_add(&gmydev.mydev, devno, 1);//初始化队列init_waitqueue_head(&(gmydev.rq));init_waitqueue_head(&(gmydev.wq));return 0;
}void __exit mychar_exit(void)
{dev_t devno = MKDEV(major, minor);cdev_del(&gmydev.mydev);unregister_chrdev_region(devno, mychar_num);
}//表示支持GPL的开源协议
MODULE_LICENSE("GPL");module_init(mychar_init);
module_exit(mychar_exit);

mychar.h

#ifndef MY_CHAR_H
#define MY_CHAR_H#include <asm/ioctl.h>#define MY_CHAR_MAGIC 'k'#define MYCHAR_IOCTL_GET_MAXLEN _IOR(MY_CHAR_MAGIC,1,int*)
#define MYCHAR_IOCTL_GET_CURLEN _IOR(MY_CHAR_MAGIC,2,int*)#endif

 testmychar_nonblockread.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>#include "mychar.h"
#include <stdio.h>int main(int argc,char *argv[])
{int fd = -1;char buf[8] = "";int ret = 0;if(argc < 2){printf("The argument is too few\n");return 1;}fd = open(argv[1],O_RDWR);   // | O_NONBLOCK);if(fd < 0){printf("open %s failed\n",argv[1]);return 2;}ret = read(fd,buf,8);if(ret < 0){printf("read data failed\n");}else{printf("buf=%s\n",buf);}close(fd);fd = -1;return 0;
}

Makfile

ifeq ($(KERNELRELEASE),)ifeq ($(ARCH),arm)
KERNELDIR ?= /home/linux/Linux_4412/kernel/linux-3.14
ROOTFS ?= /opt/4412/rootfs
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesmodules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_installclean:rm -rf  *.o  *.ko  .*.cmd  *.mod.*  modules.order  Module.symvers   .tmp_versionselse
CONFIG_MODULE_SIG=n
obj-m += mychar.oendif

 

 移除并新增内核模块

添加设备 

非阻塞读执行效果:

阻塞读效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/607363.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ES6(一部分)未完...

文章目录 ES61.ES6 let声明变量2.ES6 const声明常量3.变量解构赋值3-1解构对象3-2解构数组3-3字符串解构 4.模板字符串5.字符串扩展5-1 include函数5-2 repeat函数&#xff08;重复&#xff09; 6.数值扩展6-1二进制和八进制表示法6-2isFinite 与 isNaN方法6-3islnteger方法6-4…

Vue3+TS+Vite 构建自动导入开发环境

关注⬆️⬆️⬆️⬆️ 专栏后期更新更多前端内容 在一个使用 Vue 3、Vite 和 TypeScript 的项目中,配置 unplugin-auto-import 和 unplugin-vue-components 插件可以极大地提高开发效率,因为它们可以自动导入 Vue 相关的 API 和 Vue 组件,从而减少了手动导入的需要。 文章目…

FPGA UDP协议栈:基于88E1111,支持RGMII、GMII、SGMII三种模式,提供3套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐我这里已有的以太网方案本协议栈的 1G-UDP版本本协议栈的 10G-UDP版本本协议栈的 25G-UDP版本1G 千兆网 TCP-->服务器 方案1G 千兆网 TCP-->客户端 方案10G 万兆网 TCP-->服务器客户端 方案 3、该UDP协议栈性能4、详细设计方案设…

Hyperledger Fabric 消息协议

Fabric 中大量采用了 gRPC 消息在不同组件之间进行通信交互&#xff0c;主要包括如下几种情况&#xff1a;客户端访问 Peer 节点&#xff0c;客户端和 Peer 节点访问排序节点&#xff0c;链码容器与 Peer 节点交互&#xff0c;以及多个 Peer 节点之间的 Gossip 交互。 消息结构…

Android 架构 - 模块化

参考文章 谷歌官方指南 一、概念 将大型、复杂问题拆解成一个个小的、简单问题&#xff0c;从而可以做到各个击破。模块化简单讲就是把多功能高耦合的代码逻辑拆散成多个功能单一职责明确的模块。模块指 Android 项目中的 module&#xff0c;通常会包含 Gradle 构建脚本、源代…

【Android Studio】创建第一个APP工程及生成APK安装包

&#x1f31f;博主领域&#xff1a;嵌入式领域&人工智能&软件开发 前言&#xff1a;本文详细介绍创建Android Studio第一个APP工程及打包生成APK安装包。 如下两个博客我记录了第一次创建项目时出现的问题&#xff0c;若你也遇见了同样的问题&#xff0c;可参考&#…

QT上位机开发(会员充值软件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 所有的控件当中&#xff0c;除了label、edit、radio、combobox和button之外&#xff0c;另外一个用的比较多的控件就是grid&#xff0c;也可称之为…

数学的雨伞下:理解世界的乐趣

这本书没有一个公式&#xff0c;却讲透了数学的本质&#xff01; 《数学的雨伞下&#xff1a;理解世界的乐趣》。一本足以刷新观念的好书&#xff0c;从超市到对数再到相对论&#xff0c;娓娓道来。对于思维空间也给出了一个更容易理解的角度。 作者&#xff1a;米卡埃尔•洛奈…

WindowsServer安装mysql最新版

安装 下载相应mysql安装包&#xff1a; MySQL :: Download MySQL Installer 选择不登陆下载 双击运行下载好的mysql-installer-community-*.*.*.msi 进入类型选择页面&#xff0c;本人需要mysql云服务就选择了server only server only&#xff08;服务器&#xff09;&#x…

day11 有效的括号 删除字符串中的所有相邻重复项 逆波兰表达式求值

题目1&#xff1a;20 有效的括号 题目链接&#xff1a;20 有效的括号 题意 判断字符串是否有效&#xff0c;若有效&#xff1a; 1&#xff09;左括号必须用相应的右括号 2&#xff09;左括号的闭合顺序正确 ({)}顺序不正确&#xff0c;应该是&#xff08;{}&#xff09; …

如何使用GaussDB创建脱敏策略(MASKING POLICY)

目录 一、前言 二、GaussDB中的脱敏策略 1、数据脱敏的定义 2、创建脱敏策略的语法说明 三、在GaussDB中如何创建数据脱敏策略(示例) 1、创建脱敏策略的一般步骤 2、GaussDB数据库中创建脱敏策略的完整示例 1&#xff09;开启安全策略开关&#xff0c;以初识用户omm登录…

Qt/QML编程学习之心得:一个音频播放器的实现(29)

在window下&#xff0c;打开音乐播放器&#xff0c;然后打开一个.mp3文件&#xff0c;就可以实现播放了&#xff0c;那么在Qt/QML中如何实现呢&#xff1f;首先所有的设计都是基于音乐播放器的&#xff0c;嵌入式linux下同样也有音乐播放器&#xff0c;比如mplayer。其调用方法…

Python语法进阶学习--模块和包

在学习python进阶知识中的面向对象之前,还要了解一下当中几个概念:包、模块、类和函数。 一.模块和包 模块和包:用来组织Python代码的。 包 > 含有 __init__.py文件的文件夹模块 > py文件类 > class 【面向对象学习】函数&#xff08;方法&#xff09;> def 以上均…

Unity3D时间类Time和DateTime的用法

系列文章目录 Unity知识点 文章目录 系列文章目录前言一、Time和DataTime的区别1-1、命名空间不同 二、Time和DataTime的使用2-1、Time类2-2、代码解释如下&#xff1a;2-3、DataTime类2-4、代码解释如下&#xff1a; 三、实际应用3-1、Time类测试性能代码如下3-2、运行结果如…

小H靶场笔记:DC-7

DC-7 January 8, 2024 4:11 PM Tags&#xff1a;Drupal 8&#xff1b;Drush Owner&#xff1a;只惠摸鱼 信息收集 使用arp-scan和nmap扫描C段存活主机&#xff0c;探测到靶机ip&#xff1a;192.168.199.137&#xff0c;且开放80、22端口 探测22、80开放端口的服务、版本、操…

Mac电脑系统提速软件CleanmyMac X2024

Mac是现代人日常工作时必不可少的工具&#xff0c;尤其是在居家办公已经屡见不鲜的当下。视频会议、文档传送、视频剪辑等等。它在工作中扮演的角色越来越重要&#xff0c;所以也导致了它的流畅程度可以在很大程度上影响人们一整天的工作效率和心情。 CleanMyMac X全新版下载如…

Shiro框架:ShiroFilterFactoryBean过滤器源码解析

目录 1.Shiro自定义拦截器SpringShiroFilter 1.1 ShiroFilterFactoryBean解析 1.1.1 实现FactoryBean接口 1.1.2 实现BeanPostProcessor接口 1.2 SpringShiroFilter解析 1.2.1 OncePerRequestFilter过滤逻辑实现 1.2.2 AbstractShiroFilter过滤逻辑实现 1.2.2.1 创建Sub…

Alphalens 因子分析 - 以低换手率因子为例(1)

因子分析是量化研究的基本技能之一。通过因子分析,找出有效的因子,通过相关性去重后,就可以通过机器学习、线性回归等方法把因子组合起来,构成交易策略。 这一篇笔记我们就介绍如何使用 Alphalens 来进行单因子分析。我们使用的因子是低换手率因子。 股谚有一种说法,天量…

风速预测 | 基于深度学习的风速预测模型(Matlab)

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 风速预测 | 基于深度学习的风速预测模型&#xff08;Matlab&#xff09; 程序设计 完整程序和数据获取方式&#xff1a;私信博主回复基于深度学习的风速预测模型&#xff08;Matlab&#xff09;。 参考资料 [1] htt…

【Flutter 开发实战】Dart 基础篇:常用运算符

在Dart中&#xff0c;运算符是编写任何程序的基本构建块之一。本文将详细介绍Dart中常用的运算符&#xff0c;以帮助初学者更好地理解和运用这些概念。 1. 算术运算符 算术运算符用于执行基本的数学运算。Dart支持常见的加、减、乘、除、整除以及取余运算。常见的算数运算符如…