RTX——第15章 互斥信号量
以下内容转载自安富莱电子: http://forum.armfly.com/forum.php
本章节开始讲解 RTX 的另一个重要的资源共享机制---互斥信号量(Mutex,即 Mutual Exclusion
的缩写)。 注意,建议初学者学习完上个章节的信号量后再学习本章节的互斥信号量。
一定要多思考,二值信号会造成优先级翻转,所以在优先级有严格要求的场合,请使用互斥信号。
互斥信号量的概念及其作用
互斥信号量就是信号量的一种特殊形式,也就是信号量初始值为 1 的情况。 有些 RTOS 中也将信号量
初始值设置为 1 的情况称之为二值信号量。 为什么叫二值信号量呢?因为信号量资源被获取了,信号量值
就是 0,信号量资源被释放,信号量值就是 1,把这种只有 0 和 1 两种情况的信号量称之为二值信号量。
互斥信号量的主要作用就是对资源实现互斥访问。 下面举一个通过二值信号量实现资源独享,即互斥访问
的例子,让大家有一个形象的认识
运行条件:
让两个任务 Task1 和 Task2 都有运行串口打印 printf,这里我们就对函数 printf 通过二值信号量实
现互斥访问。 如果不对函数 printf 进行互斥访问,串口打印容易出现乱码。
用信号量实现二值信号量只需将信号量的初始值设置为 1 即可。
互斥信号量跟二值信号量又有什么区别呢?互斥信号量可以防止优先级翻转,而二值信号量不支持,下面我们就讲解一下优先级翻转问题。
运行条件:
创建 3 个任务 Task1,Task2 和 Task3,优先级分别为 3,2,1。 也就是 Task1 的优先级最高
任务 Task1 和 Task3 互斥访问串口打印 printf,采用二值信号实现互斥访问。
起初 Task3 通过二值信号量正在调用 printf,被任务 Task1 抢占,开始执行任务 Task1,也就是上图
的起始位置。
运行过程描述如下:
任务 Task1 运行的过程需要调用函数 printf,发现任务 Task3 正在调用,任务 Task1 会被挂起,等
待 Task3 释放函数 printf。
在调度器的作用下,任务 Task3 得到运行,Task3 运行的过程中,由于任务 Task2 就绪,抢占了 Task3
的运行。 优先级翻转问题就出在这里了,从任务执行的现象上看,任务 Task1 需要等待 Task2 执行
完毕才有机会得到执行,这个与抢占式调度正好反了,正常情况下应该是高优先级任务抢占低优先级
任务的执行,这里成了高优先级任务 Task1 等待低优先级任务 Task2 完成。 所以这种情况被称之为
优先级翻转问题。
任务 Task2 执行完毕后,任务 Task3 恢复执行,Task3 释放互斥资源后,任务 Task1 得到互斥资源,
从而可以继续执行。
上面就是一个产生优先级翻转问题的现象。
RTX 互斥信号量的实现
RTX 互斥信号量是怎么实现的呢?其实相比二值信号量就是解决了一下优先级翻转的问题。 下面我们
通过如下的框图来说明一下 RTX 互斥信号量的实现,让大家有一个形象的认识。
运行条件:
创建 2 个任务 Task1 和 Task2,优先级分别为 1 和 3,也就是任务 Task2 的优先级最高
任务 Task1 和 Task2 互斥访问串口打印 printf。
使用 RTX 的互斥信号量实现串口打印 printf 的互斥访问。
运行过程描述如下:
低优先级任务 Task1 执行过程中先获得互斥资源 printf 的执行。 此时任务 Task2 抢占了任务 Task1
的执行,任务 Task1 被挂起。 任务 Task2 得到执行。
任务 Task2 执行过程中也需要调用互斥资源,但是发现任务 Task1 正在访问,此时任务 Task1 的优
先级会被提升到跟 Task2 同一个优先级,也就是优先级 3,这个就是所谓的优先级继承(Priority
inheritance),这样就有效的防止了优先级翻转问题。 任务 Task2 被挂起,任务 Task1 有新的优先
级继续执行。
任务 Task1 执行完毕并释放互斥资源后,优先级恢复到原来的水平。 由于互斥资源可以使用,任务
Task2 获得互斥资源后开始执行。
上面就是一个简单 RTX 互斥信号量的实现过程。
互斥信号量仅支持用在 RTX 的任务中,中断函数中不可使用。
互斥信号量 API 函数
使用如下 3 个函数可以实现 RTX 的互斥信号量:
os_mut_init
os_mut_release
os_mut_wait
函数 os_mut_init
函数原型:
void os_mut_init (
OS_ID mutex ); /* OS_MUT 类型变量 */
函数描述:
函数 os_mut_init 用于互斥信号量的初始化并设置初始值。
第 1 个参数填写数据类型为 OS_MUT 的变量,同时也作为 ID 标识
使用这个函数要注意以下问题:
1. 函数的参数必须是 OS_MUT 类型的。
函数 os_mut_wait
函数原型:
OS_RESULT os_mut_wait (
OS_ID mutex, /* OS_MUT 类型变量 */
U16 timeout ); /* 超时时间 */
函数描述:
函数 os_mut_wait 用于获取互斥信号量资源,如果互斥资源可用,那么调用函数 os_mut_wait 后可以成
功获取互斥资源,在此函数的源码将计数值加 1(互斥信号量源码的实现上跟信号量不同)。如果互斥资
源不可用,调用此函数的任务将由运行态转到挂起态,等待信号量资源可用,也就是计数值为 0 的时候。
如果一个低优先级的任务通过互斥信号量正在访问互斥资源,那么当一个高优先级的任务也通过互斥
信号量访问这个互斥资源的话,会将这个低优先级任务的优先级提升到和高优先级任务一样的优先级,这
就是所谓的优先级继承,通过优先级继承可以有效防止优先级翻转问题。 当低优先级任务释放了互斥资源
之后,重新恢复到原来的优先级。
第 1 个参数填写数据类型为 OS_MUT 的变量,同时也作为 ID 标识
第 2 个参数表示设在的等待时间,范围 0-0xFFFF,当参数设置为 0-0xFFFE 时,表示等待这么多个
时钟节拍,参数设置为 0xFFFF 时表示无限等待直到互斥资源可用。
函数返回 OS_R_MUT 表示函数设置的超时时间范围内收到互斥信号量可用资源。
函数返回 OS_R_TMO 表示超时。
函数返回 OS_R_OK 表示无需等待,立即获得互斥资源。
使用这个函数要注意以下问题:
1. 使用此函数前一定要调用函数 os_mut_init 进行初始化。
函数 os_mut_release
函数原型:
OS_RESULT os_mut_release (
OS_ID mutex ); /* OS_MUT 类型变量 */
函数描述:
函数 os_mut_release 用于释放互斥资源,调用此函数会将计数值减 1。只有当计数值减到 0 的时候其它
的任务才可以获取互斥资源。 也就是说如果用户调用 os_mut_wait 和 os_mut_release,需要配套使用。
通过函数 os_mut_wait 实现互斥信号量计数值加 1,通过函数 os_mut_release 实现互斥信号量计数值减
1 操作,这样的话,这两个函数可以实现嵌套调用,但是一定要保证成对调用,要不会造成互斥资源无法
正确释放。
如果拥有互斥资源的任务的优先级被提升了,那么此函数会恢复任务以前的优先级。
第 1 个参数参数填写数据类型为 OS_MUT 的变量,同时也作为 ID 标识。
返回值 OS_R_OK,表示互斥信号量成功释放。
返回值 OS_R_NOR,表示互斥信号量的内部计数值已经是 0 或者调用此函数的任务不是互斥资源的
拥有者。
使用这个函数要注意以下问题:
1. 使用此函数前一定要调用函数 os_mut_init 进行初始化。
实验练习场:
实验目的:
1. 学习 RTX 的互斥信号量
实验内容:
在调用 printf 函数的地方都加上互斥信号量,防止多个任务调用此函数造成冲突,以至于串口打印出现乱码。
可以看出我们的代码是为了保护printf函数这个共享函数(资源)的。
注意,互斥信号,创建的时候初始值为1。
这里要说明的是,都采取的是永久等待,可根据具体项目需要更改等待时间。获取(等待)互斥信号和释放互斥信号应该在同一个任务中成对出现(虽然这里可以有其他“黑科技”,但我并不想让更多的人知道,因为那样通常没有什么好处,按照官方的参考demo写,一定更规范和正确)。
简要说明程序流程:先创建互斥信号,初始化默认是1,这样其他任务调用wait函数(获取也叫等待)时,第一个调用wait函数并调用printf函数的任务一定会完整不受干扰执行printf的打印,其他也有调用printf函数的必须等待,在第一个调用任务执行完保护的函数之后,要释放互斥信号,即release函数,这样其他调用printf的任务才不至于永久等待。
程序输出:
RTX——第15章 互斥信号量的更多相关文章
- 【二代示波器教程】第15章 FreeRTOS操作系统版本二代示波器实现
第15章 FreeRTOS操作系统版本二代示波器实现 本章教程为大家讲解FreeRTOS操作系统版本的二代示波器实现.主要讲解RTOS设计框架,即各个任务实现的功能,任务间的通信方案选择,任务 ...
- Linux就这个范儿 第15章 七种武器 linux 同步IO: sync、fsync与fdatasync Linux中的内存大页面huge page/large page David Cutler Linux读写内存数据的三种方式
Linux就这个范儿 第15章 七种武器 linux 同步IO: sync.fsync与fdatasync Linux中的内存大页面huge page/large page David Cut ...
- 【RL-TCPnet网络教程】第15章 RL-TCPnet之创建多个TCP连接
第15章 RL-TCPnet之创建多个TCP连接 本章节为大家讲解RL-TCPnet的TCP多客户端实现,因为多客户端在实际项目中用到的地方还挺多,所以我们也专门开启一个章节做讲解.另外,学习 ...
- FreeRTOS 二值信号量,互斥信号量,递归互斥信号量
以下转载自安富莱电子: http://forum.armfly.com/forum.php 本章节讲解 FreeRTOS 任务间的同步和资源共享机制,二值信号量. 二值信号量是计数信号量的一种特殊形式 ...
- 第15章 LinkedList类(暂无)
第15章 LinkedList类 LinkedList类是
- ASM:《X86汇编语言-从实模式到保护模式》第15章:任务切换
15章其实应该是和14章相辅相成的(感觉应该是作者觉得14章内容太多了然后切出来了一点).任务切换和14章的某些概念是分不开的. ★PART1:任务门与任务切换的方法 1. 任务管理程序 14章的时候 ...
- 第15章 设备无关位图_15.3 DIB和DDB的结合
第15章 设备相关位图_15.3 DIB和DDB的结合 15.3.1 从DIB创建DDB (1)hBitmap =CreateDIBitmap(…)——注意这名称会误导,实际上创建的是DDB 参数 说 ...
- unix network programming(3rd)Vol.1 [第13~15章]《读书笔记系列》
第13章 守护进程和inetd 超级服务器 syslog() daemon_init() setuid() setgid() 第14章 高级IO 标准I/O函数库,支持3种缓冲 缓冲(读写存储设备(硬 ...
- 《Android开发艺术探索》读书笔记 (13) 第13章 综合技术、第14章 JNI和NDK编程、第15章 Android性能优化
第13章 综合技术 13.1 使用CrashHandler来获取应用的Crash信息 (1)应用发生Crash在所难免,但是如何采集crash信息以供后续开发处理这类问题呢?利用Thread类的set ...
随机推荐
- EXCEPTION-IBATIS
CreateTime--2016年8月23日08:44:03Author:Marydonibatis的sqlMap的xml文件配置出现的异常信息及解决方案 声明:异常类文章主要是记录了我遇到的异常 ...
- 关于NHibernate中存在于Session中实例的3种状态的简单分析
在使用NHibernate的时候.在Session中会有3种状态. 1. 瞬时状态 (Transient) 由 new 命令开辟内存空间的对象,也就是平时所熟悉的普通对象. 如: Student st ...
- [Done]SnowFlake 分布式环境下基于ZK构WorkId
Twitter 的 Snowflake 大家应该都熟悉的,先上个图: 时间戳 序列号一般不会去改造,主要是工作机器id,大家会进行相关改造,我厂对工作机器进行了如下改造(估计大家都差不多吧,囧~~~ ...
- Oracle常见的异常处理
总结了在操作数据库的时候常常遇见的Oracle异常以及处理方法. 代码 提示 备注 一般处理方法 ORA-01861 文字与格式字符串不匹配- ORA-00904 invalid column nam ...
- 微软 Visual Studio 2017 中文正式版下载 – 免费社区版/专业版/企业版
作为“宇宙最强”的集成开发环境 IDE,微软的 Visual Studio 不仅破天荒发布了 macOS 版本,如今终于也推出了其 Windows 的最新版本—— VS 2017 正式版了.这对开发者 ...
- 转:【微信小程序常见问题】下拉框选择器设置picker属性。(包括:城市、日期和时间选择器)
1.picker写法(支持日期Date.时间Time和城市自定义) wxml文件 <picker bindchange="bindPickerChange" value=&q ...
- ORA-04089: 无法对 SYS 拥有的对象创建触发器
ORA-04089: 无法对 SYS 拥有的对象创建触发器 http://bbs.csdn.net/topics/390355220 猛然发现自己是用sys用户创建表空间,创建用户,赋权,顺手就把sq ...
- HDUOJ--------(1198)Farm Irrigation
Farm Irrigation Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- Windows命令-route
Windows route命令 添加一条永久网关:route add 0.0.0.0 mask 0.0.0.0 192.168.2.1 -p例如: route -p add 192.168.0.0 m ...
- 【php】基础学习3
本节主要是php中函数的学习: <html xmlns=http://www.w3.org/1999/xhtml> <head> <meta http-equiv=Con ...