以下内容转载自安富莱电子: 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章 互斥信号量的更多相关文章

  1. 【二代示波器教程】第15章 FreeRTOS操作系统版本二代示波器实现

    第15章     FreeRTOS操作系统版本二代示波器实现 本章教程为大家讲解FreeRTOS操作系统版本的二代示波器实现.主要讲解RTOS设计框架,即各个任务实现的功能,任务间的通信方案选择,任务 ...

  2. 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 ...

  3. 【RL-TCPnet网络教程】第15章 RL-TCPnet之创建多个TCP连接

    第15章     RL-TCPnet之创建多个TCP连接 本章节为大家讲解RL-TCPnet的TCP多客户端实现,因为多客户端在实际项目中用到的地方还挺多,所以我们也专门开启一个章节做讲解.另外,学习 ...

  4. FreeRTOS 二值信号量,互斥信号量,递归互斥信号量

    以下转载自安富莱电子: http://forum.armfly.com/forum.php 本章节讲解 FreeRTOS 任务间的同步和资源共享机制,二值信号量. 二值信号量是计数信号量的一种特殊形式 ...

  5. 第15章 LinkedList类(暂无)

    第15章 LinkedList类 LinkedList类是

  6. ASM:《X86汇编语言-从实模式到保护模式》第15章:任务切换

    15章其实应该是和14章相辅相成的(感觉应该是作者觉得14章内容太多了然后切出来了一点).任务切换和14章的某些概念是分不开的. ★PART1:任务门与任务切换的方法 1. 任务管理程序 14章的时候 ...

  7. 第15章 设备无关位图_15.3 DIB和DDB的结合

    第15章 设备相关位图_15.3 DIB和DDB的结合 15.3.1 从DIB创建DDB (1)hBitmap =CreateDIBitmap(…)——注意这名称会误导,实际上创建的是DDB 参数 说 ...

  8. unix network programming(3rd)Vol.1 [第13~15章]《读书笔记系列》

    第13章 守护进程和inetd 超级服务器 syslog() daemon_init() setuid() setgid() 第14章 高级IO 标准I/O函数库,支持3种缓冲 缓冲(读写存储设备(硬 ...

  9. 《Android开发艺术探索》读书笔记 (13) 第13章 综合技术、第14章 JNI和NDK编程、第15章 Android性能优化

    第13章 综合技术 13.1 使用CrashHandler来获取应用的Crash信息 (1)应用发生Crash在所难免,但是如何采集crash信息以供后续开发处理这类问题呢?利用Thread类的set ...

随机推荐

  1. Json动态添加属性

    一维Json: var Json={}: Json.name="小明"; Json.age="12": Json.sex="男": 输出效果 ...

  2. HTML5 CANVAS 弹幕插件

    概述 修改了普通弹幕运动的算法,新增了部分功能 详细 代码下载:http://www.demodashi.com/demo/10595.html 修改了普通弹幕运动的算法,新增了部分功能,具体请参看附 ...

  3. <转>字符编码笔记:ASCII,Unicode和UTF-8

    本文转自:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html 今天中午,我突然想搞清楚Unicode和UTF-8之间 ...

  4. poj----Maximum sum(poj 2479)

    Maximum sum Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30704   Accepted: 9408 Desc ...

  5. skimage exposure模块解读

    exposure模块包括: 直方图均衡化 gamma调整.sigmoid调整.log调整 判断图像是否对比度太低 exposure模块包括以下函数: histogram 统计颜色的直方图,基于nump ...

  6. jseclipse 是eclipse插件,让你编写js代码感觉更爽

    一直以来都没有客意的去找一下eclipse下面的javascript开发插件,今天在网上无意发现了一个,回去试了一下,感觉不错.写JS代码根写PHP代码差不多感觉挺爽的.JSEclipse是个Ecli ...

  7. Python练习笔记——计算个人体重指数

    输入您的身高 体重 性别 计算出你的体重是否标准 gender = input('请输入您的性别(boy or girl):') height = input('请输入您的身高(单位cm):') he ...

  8. PO_本地一揽子采购协议(流程)

    2014-06-04 Created By BaoXinjian

  9. Android JSBridge的原理与实现

    在Android中.JSBridge已经不是什么新奇的事物了,各家的实现方式也略有差异. 大多数人都知道WebView存在一个漏洞.见WebView中接口隐患与手机挂马利用,尽管该漏洞已经在Andro ...

  10. HDU1024 Max Sum Plus Plus 【DP】

    Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...