嵌入式驱动学习第一周——阻塞IO,进程的休眠与唤醒

前言

   本文介绍进程的休眠与唤醒。

   嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程,未来预计四个月将高强度更新本专栏,喜欢的可以关注本博主并订阅本专栏,一起讨论一起学习。现在关注就是老粉啦!

行文目录

  • 前言
  • 1. 阻塞和非阻塞
  • 2. 进程的几种状态
  • 3. 等待队列
    • 3.1 等待队列头
    • 3.2 等待队列项
  • 参考资料

1. 阻塞和非阻塞

   当应用程序对设备驱动进行操作时,如果不能获取到设备资源,那么阻塞IO就会将应用程序挂起,直到设备资源可以获取为止。其模式如下所示:

在这里插入图片描述

   应用程序调用read函数从设备中读取数据,当设备不可用或数据未准备好的时候进入到休眠态,等设备可用就会从休眠态唤醒,然后从设备中读取数据返回到应用程序。

   阻塞访问最大的好处就是当设备文件不可操作时进程进入休眠态,可以把CPU资源让出来。

   应用程序用阻塞IO访问的代码如下。默认读取方式就是阻塞式访问。

int fd;
int data = 0;

fd = open("dev/xxx_dev", O_RDWR);			// 阻塞方式打开
ret = read(fd, &data, sizeof(data));		// 读取数据

   非阻塞式IO中,应用程序对应的线程不会挂起,要么一直轮询等待,直到设备资源可用,要么直接放弃,其模式如下:

在这里插入图片描述

   应用程序调用read函数从设备中获取数据,当设备不可用或数据未准备好时会立即向内核返回一个错误码,表示数据读取失败,应用程序会再次重新读取数据,这样循环往复,直到数据读取成功。

   应用程序用阻塞IO访问的代码如下,主要在open函数的第二个参数上有变化:

int fd;
int data = 0;

fd = open("dev/xxx_dev", O_RDWR | O_NONBLOCK);			// 阻塞方式打开
ret = read(fd, &data, sizeof(data));		// 读取数据

2. 进程的几种状态

TASK_RUNNING: 正在运行或处于就绪状态:就绪状态是指进程申请到了CPU以外的其他所有资源,提醒:一般的操作系统教科书将正在CPU上执 行的进程定义为RUNNING状态、而将可执行但是尚未被调度执行的进程定义为READY状态,这两种状态在Linux下统一为 TASK_RUNNING状态.
  
TASK_INTERRUPTIBLE: 处于等待队伍中,等待资源有效时唤醒(比如等待键盘输入、socket连接、信号等等),但可以被中断唤醒.一般情况下,进程列表中的绝大多数进程都处于 TASK_INTERRUPTIBLE状态.毕竟皇帝只有一个(单个CPU时),后宫佳丽几千;如果不是绝大多数进程都在睡眠,CPU又怎么响应得过来.
  
TASK_UNINTERRUPTIBLE:处于等待队伍中,等待资源有效时唤醒(比如等待键盘输入、socket连接、信号等等),但不可以被中断唤醒.
  
TASK_ZOMBIE:僵死状态,进程资源用户空间被释放,但内核中的进程PCB并没有释放,等待父进程回收.
  
TASK_STOPPED:进程被外部程序暂停(如收到SIGSTOP信号,进程会进入到TASK_STOPPED状态),当再次允许时继续执行(进程收到SIGCONT信号,进入TASK_RUNNING状态),因此处于这一状态的进程可以被唤醒.

3. 等待队列

   阻塞访问中,如果设备不可操作的时候,进程进入休眠态,但当设备文件可以操作时就必须唤醒进程,一般在终端中完成唤醒工作。Linux内核提供等待队列来实现阻塞进程的唤醒工作。

3.1 等待队列头

   如果要使用等待队列,必须先新建并初始化一个等待队列头,等待队列头使用结构体wait_queue_head_t

struct __wait_queue_head {
	spinlock_t lock;
	struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;

   定义好等待队列头后就使用函数init_waitqueue_head进行初始化。

/*
 * @description: 初始化等待队列头
 * @param-q    : 要初始化的等待队列头
 * @return     : 无
 */
void init_waitqueue_head(wait_queue_head_t *q)

3.2 等待队列项

   等待队列头是一个等待队列的头部,每个访问设备的进程为一个队列项,当设备不可用时将这些进程对应的等待队列项添加到等待队列中,用结构体wait_queue_t表示等待队列项

struct __wait_queue {
	unsigned int flags;
	void *private;
	wait_queue_func_t func;
	struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;

   DECLARE_WAITQUEUE 定义并初始化一个等待队列项

// 定义并初始化一个等待队列,name是等待队列项的名字,tsk是该等待队列项属于哪个任务(进程),一般设置为current
DECLARE_WAITQUEUE(name, tsk)

   以下是添加等待队列项的函数:

/*
 * @description: 添加队列项
 * @param-q    : 等待队列项要加入的等待对猎头
 * @param-wait : 要加入的等待队列项
 * @return     : 无
 */
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)

   以下是删除等待队列项的函数:

/*
 * @description: 删除队列项
 * @param-q    : 要删除等待队列项的等待对猎头
 * @param-wait : 要删除的等待队列项
 * @return     : 无
 */
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)

   唤醒休眠态进程有两个函数wake_up()wake_up_interruptible()

wake_up 可以唤醒处于TASK_INTERRUPTIBLETASK_UNINTERRUPTIBLE状态的进程
wake_up_interruptible只可以唤醒处于TASK_INTERRUPTIBLE的进程

/*
 * @description: 环境休眠态的进程
 * @param-q    : 要唤醒的等待队列头,其中的所有线程都会唤醒
 * @return     : 无
 */
void wake_up(wait_queue_head_t *q)
void wake_up_interruptible(wait_queue_head_t *q)

   除了主动唤醒,也可以设置等待队列等待某个事件来唤醒等待队列的线程。

/*
 * @description    : 当condition为真时,唤醒以wq为等待对猎头的等待队列,condition为假时,会一直阻塞。
 * 					此函数会将进程设置为TASK_UNINTERRUPTIBLE 状态
 * @param-wq       : 要唤醒的等待队列头,其中的所有线程都会唤醒
 * @param-condition: 唤醒条件
 * @return         : 无
 */
wait_event(wq, condition)
/*
 * @description    : 功能和 wait_event 类似,但是此函数可以添加超时时间,以 jiffies 为单位
 * @param-wq       : 要唤醒的等待队列头,其中的所有线程都会唤醒
 * @param-condition: 唤醒条件
 * @param-timeout  : 超时时间
 * @return         : 0,表示超时时间到,而且 condition为假。1,表示 condition 为真,也就是条件满足了
 */
wait_event_timeout(wq, condition, timeout)
/*
 * @description    : 与 wait_event 函数类似,但是此函数将进程设置为 TASK_INTERRUPTIBLE,就是可以被信号打断
 */
wait_event_interruptible(wq, condition)
/*
 * @description    : 与 wait_event_timeout 函数类似,但是此函数将进程设置为 TASK_INTERRUPTIBLE,就是可以被信号打断
 */
wait_event_interruptible_timeout(wq, condition, timeout)

总结:使用等待队列实现阻塞访问重点注意两点:

①、将任务或者进程加入到等待队列头
②、在合适的点唤醒等待队列,一般都是中断处理函数里面。

参考资料

[1] 【正点原子】I.MX6U嵌入式Linux驱区动开发指南 第五十二章

[2] linux内核任务调度-- wait_event

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【TEE】内存完整性保护

Hash Functions&Merkle Tree 对读操作进行完整性检查,通过在加载的块上重新计算一个哈希,然后根据片外地址将得到的哈希与片上哈希比较。 缺点:不可承受的片上存储开销,并假设128位哈希和512位cache line,其开销为…

基于springboot+vue的实习管理系统

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

8个优秀的CSS实践,开发web应用

HTML面试题部分 1.H5的新特性有哪些 2.Label的作用是什么?是怎么用的? 3.HTML5的form如何关闭自动完成功能 4.dom如何实现浏览器内多个标签页之间的通信? 5.实现不使用 border 画出1px高的线,在不同浏览器的标准模式与怪异模式下都 能保持一…

Qt/自定义控件的封装

新建文件,选择Qt设计师界面类 创建空界面 这是自己控件封装的文件,双击跳转到设计界面进行设计 跳转到其他的ui界面,创建一个widget 右键,选择提升为 在提升的类名称输入刚刚创建的类名,添加后选择提升,勾选…

FairTune:优化参数高效微调以实现医学图像分析的公平性

paper:https://arxiv.org/abs/2310.05055 code: https://github.com/Raman1121/FairTune 摘要和介绍 人工智能在医疗健康应用中的应用正在迅速增长。然而,人工智能模型一再被证明对不同的人口统计学亚群体表现出不必要的偏见——AI模型在由…

【暗月安全】2021年渗透测试全套培训视频

参与培训需要遵守国家法律法规,相关知识只做技术研究,请勿用于违法用途,造成任何后果自负与本人无关。 中华人民共和国网络安全法(2017 年 6 月 1 日起施行) 第二十二条 任何个人和组织不得从事入侵他人网络、干扰他…

数据结构之七大排序

𝙉𝙞𝙘𝙚!!👏🏻‧✧̣̥̇‧✦👏🏻‧✧̣̥̇‧✦ 👏🏻‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - :来于“云”的“羽球人”。…

Kubernetes Service

一、Service:Kubernetes 中的服务返现与负载均衡 1、为什么需要服务发现 Pod 生命周期短暂,IP 地址随时变化。 Deployment 等的 Pod 组需要统一访问入口和做负载均衡。 应用间在不同环境部署时保持同样的部署拓扑和访问方式。 2、应用服务如何暴露到…

停止Tomcat服务的方式

运行脚本文件停止 运行Tomcat的bin目录中提供的停止服务的脚本文件 关闭命令 # sh方式 sh shutdown.sh# ./方式 ./shutdown.sh操作步骤 运行结束进程停止 查看Tomcat进程,获得进程id kill进程命令 # 执行命令结束进程 kill -9 65358 操作步骤 注意 kill命令是…

简单的排序算法

目录 1.直接插入排序 2.希尔排序 3.选择排序 4.冒泡排序 5.计数排序 6.排序总结 1.直接插入排序 (1)思想 所谓插入排序,就是将待排序数据插入到已经有序的数据中,为了使插入后数据依然有序,就要选中一个合理的…

android开发网络通信,带你彻底搞懂Android启动速度优化

实现方案 直接依赖 这种方式实现简单,但是耦合太严重,不方便维护与开发,当工程逐渐增大模块逐渐增多,依赖关系会非常复杂,不推荐这种方式。 事件或广播通信 EventBus: 我们非常熟悉的事件总线型的通信框…

JavaScript的`bind`方法:函数的“复制”与“定制”

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

jquery选择器有哪些

jQuery是一个功能强大的JavaScript库,它提供了丰富的选择器来帮助开发者更方便地选择和操作DOM元素。以下是jQuery的一些常用选择器及其示例代码: 1.基本选择器: // 通过ID选择元素 $("#myId").css("color", "red…

【论文阅读 VLDB22】On-Demand State Separation for Cloud Data Warehousing

On-Demand State Separation for Cloud Data Warehousing 问题背景 首先是问题背景,目前除了大规模PB级别的AP会使用云数据库,越来越多的百G大小的中小规模的负载也开始进行上云分析和处理,而这些ap任务不需要消耗整个集群的资源&#xff0…

DHCP自动获取IP地址实验(思科)

华为设备参考:DHCP自动获取IP地址实验(华为) 一,实验目的 路由器搭载DHCP,让PC通过DHCP自动获取IP地址 二,不划分vlan 实验拓扑 配置命令 Switch Switch>enable Switch#configure terminal Switch(c…

C#不可识别的数据库格式解决方法

1.检查数据库文件路径和文件名: 确保指定的路径和文件名拼写正确,而且文件确实存在于指定的位置。使用绝对路径或相对路径都是可行的,但要确保路径的正确性 string connectionString "ProviderMicrosoft.ACE.OLEDB.12.0;Data SourceE:…

go 程序被意外kill后出现僵尸进程解决方案

go 管理自身子进程(防止僵尸进程出现) 写这篇文章是因为最近有同事竟然会知道异步启动子进程,不会关闭,最后导致导致僵尸进程出现,而且由于子进程会随着业务的使用越开越多,主进程一旦被kill掉就会不得不手动一个一个kill。 大概…

【车辆安全管理】强制降速系统

在很久之前,我们就讨论过车辆强制降速系统的重要性,即使驾驶人故意撞人,也难以做到,因为强制降速系统会控制车辆的速度。强降速系统可以通过多种传感器进行智能分析,即使降速。 汽车的Robot化概念-CSDN博客 最近发生…

LiveGBS流媒体平台GB/T28181功能-集中录像存储前端设备录像回看解决方案设备录像|云端录像|实时录像说明

LiveGBS集中录像存储前端设备录像回看解决方案设备录像|云端录像|实时录像说明 1、平台概述2、视频录像2.1、设备录像2.1.1、存储位置2.1.1.1、下级硬件设备2.1.1.2、下级国标平台 2.1.2、页面操作2.1.2.1、国标设备2.1.2.1.1、查看通道2.1.2.1.1.1、设备录像 2.1.2.1.2、配置中…

城市平均高温、平均低温数据爬取与可视化

爬取历史天气网站数据 从天气网站爬取指定城市、指定时间范围内的天气数据,并将数据保存为CSV文件。具体而言,它使用了Selenium库来模拟浏览器行为,以便获取动态加载的页面内容。 主要步骤如下: 读取城市信息和代理IP信息&…