嵌入式驱动学习第一周——linux的休眠与唤醒

news2024/9/28 7:27:08

前言

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

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

行文目录

  • 前言
  • 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

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

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

相关文章

Doris实战——美联物业数仓

目录 一、背景 1.1 企业背景 1.2 面临的问题 二、早期架构 三、新数仓架构 3.1 技术选型 3.2 运行架构 3.2.1 数据模型 纵向分域 横向分层 数据同步策略 3.2.2 数据同步策略 增量策略 全量策略 四、应用实践 4.1 业务模型 4.2 具体应用 五、实践经验 5.1 数据…

【Java EE】线程安全的集合类

目录 🌴多线程环境使用 ArrayList🎍多线程环境使⽤队列🍀多线程环境使⽤哈希表🌸 Hashtable🌸ConcurrentHashMap ⭕相关面试题🔥其他常⻅问题 原来的集合类, 大部分都不是线程安全的. Vector, Stack, HashT…

EndNote 21:文献整理与引用,一键轻松搞定 mac/win版

EndNote 21是一款功能强大的文献管理软件,专为学术研究者、学生和教师设计。它提供了全面的文献管理解决方案,帮助用户轻松整理、引用和分享学术文献。 EndNote 21软件获取 EndNote 21拥有直观的用户界面和强大的文献检索功能,用户可以轻松地…

昇腾ACL应用开发之硬件编解码dvpp

1.前言 在我们进行实际的应用开发时,都会随着对一款产品或者AI芯片的了解加深,大家都会想到有什么可以加速预处理啊或者后处理的手段?常见的不同厂家对于应用开发的时候,都会提供一个硬件解码和硬件编码的能力,这也是抛…

【C++干货基地】揭秘C++11常用特性:内联函数 | 范围for | auto自动识别 | nullptr指针空值

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 引入 哈喽各位铁汁们好啊,我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发,不知道各位的…

基于springboot实现校园爱心捐赠互助管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现校园爱心捐赠互助管理系统演示 摘要 随着互联网及电子商务平台的飞速发展,利用在线平台实现的二手商品交易以及在线捐赠已经非常普遍,很多高校目前还存在贫困生需要通过爱心人士的捐助来完成学业,同时很多高校的大学生也希…

【C++】STL学习之旅——初识STL,认识string类

string类 1 STL 简介2 STL怎么学习3 STL缺陷4 string4.1 初识 string4.2 初步使用构造函数成员函数 5 小试牛刀Thanks♪(・ω・)ノ谢谢阅读!!!下一篇文章见!!! 1 STL 简介 …

PyCharm如何添加python库

1.使用pip命令在国内源下载需要的库 下面使用清华源,在cmd中输入如下命令就可以了 pip install i https://pypi.tuna.tsinghua.edu.cn/simple 包名版本号2.如果出现报错信息,Cannot unpack file…这种情况,比如下面这种 ERROR: Cannot unpa…

考研复试指南

1. 记住,复试的本质不是考试,而是一场自我展示。 考研复试并非简单的知识考察,更是一场展示自我能力和潜力的机会。除了学科知识,考官更关注你的综合素质、学术兴趣和未来发展规划。因此,要保持自信,用更全…

前端canvas项目实战——简历制作网站(五):右侧属性栏(字体、字号、行间距)

目录 前言一、效果展示二、实现步骤1. 优化代码,提取常量2. 实现3个编辑模块3. 实现updateFontProperty方法4. 一个常见的用法:仅更新当前选中文字的样式 三、Show u the code后记 前言 上一篇博文中,我们扩充了线条对象(fabric.…

带你快速初步了解Python字典

1.字典 定义多个数据一般使用列表,但是列表也存在一定的缺陷 若列表中有多个元素,想访问其中某个元素,比较不方便 定义字典的语法:{key1:value1, key2:value2, key3:value3......} 字典和列表习惯的使用场景: &qu…

(3)(3.1) FlightDeck FrSky发射器应用程序

文章目录 前言 1 概述 2 Turnkey Packages 3 参数说明 前言 ​Craft and Theory 的 FlightDeck 可让你轻松查看飞行模式、高度、速度、姿态和关键系统警报,包括故障保护和电池错误,如电池不平衡警告和发射机低电量警报。 1 概述 Craft and Theory 的…

Jmeter 安装

JMeter是Java的框架,因此在安装Jmeter前需要先安装JDK,此处安装以Windows版为例 1. 安装jdk:Java Downloads | Oracle 安装完成后设置环境变量 将环境变量JAVA_HOME设置为 C:\Program Files\Java\jdk1.7.0_25 在系统变量Path中添加 C:\Pro…

【NR 定位】3GPP NR Positioning 5G定位标准解读(一)

目录 前言 1. 3GPP规划下的5G技术演进 2. 5G NR定位技术的发展 2.1 Rel-16首次对基于5G的定位技术进行标准化 2.2 Rel-17进一步提升5G定位技术的性能 3. Rel-18 关于5G定位技术的新方向、新进展 3.1 Sidelink高精度定位功能 3.2 针对上述不同用例,3GPP考虑按…

JAVAEE初阶 JVM(二)

垃圾回收和双亲委派模型 1.双亲委派模型2.垃圾回收机制(1) 识别垃圾1.引用计数2.可达性分析 (2) 销毁垃圾1.标记清除2.复制算法3.标记整理 3.分代回收 1.双亲委派模型 描述了如何查找.class文件的策略. 同时JVM中有专门进行类加载的操作,有一个模块,叫做类加载器. 上述就是为了…

安装Realtek Audio Driver失败[Error Code:-0001]

安装Realtek Audio Driver失败[Error Code:-0001] 首先来看一下我们遇到的问题GPT4的推荐解决方法(流水账)笔者自己真实有效的解决办法 首先来看一下我们遇到的问题 描述:在笔记本更新完电脑之后,没有自带声音驱动。然…

实例:NX二次开发收集关于Open C的计时信息

目录 一、概述 二、实现的功能 三、代码实现以及详细解析 一、概述 在NX二次开发过程中,我们为了效率经常会进行Open C的计时统计,这个实例可用于收集关于Open C的计时信息程序,并且在计时测试中很有用。该实例通过UF_begin_timer启动一个…

Pyglet图形界面版2048游戏——详尽实现教程(上)

目录 Pyglet图形界面版2048游戏 一、色块展示 二、绘制标题 三、方阵色块 四、界面布局 五、键鼠操作 Pyglet图形界面版2048游戏 一、色块展示 准备好游戏数字的背景颜色,如以下12种: COLOR ((206, 194, 180, 255), (237, 229, 218, 255), (23…

首例以“冠状病毒”为主题的勒索病毒,篡改系统MBR

前言概述 2020年勒索病毒攻击仍然是网络安全的最大威胁,在短短三个月的时间里,已经出现了多款新型的勒索病毒,关于2020年勒索病毒攻击新趋势,可以阅读笔者写的上一篇文章,里面有详细的分析,从目前观察到的…

深入解剖指针(4)

个人主页(找往期文章包括但不限于本期文章中不懂的知识点): 我要学编程(ಥ_ಥ)-CSDN博客 目录 回调函数 qsort使用举例 使用qsort函数排序整型数据 使用qsort排序结构数据 qsort函数的模拟实现 回调函数 回调函数就是一个通过函数指…