RTX——第14章 信号量
以下内容转载自安富莱电子: http://forum.armfly.com/forum.php
本章节开始讲解 RTX 的另一个重要的任务间的同步和资源共享机制,信号量。
信号量有3种用途:
1) 表达事件的发生次数或者已发生事件的数量。
2) 表达资源可用性,例如有一台打印机,信号量值为1表示打印机空闲, 为0表示打印机被占用。这是资源可用量的一个特例,也可以说,信号量值为1表示有1台打印机空闲,为0表示无打印机空闲。
3) 表达资源可用量,例如有10个串口,信号量值用于表达空闲串口数量
实际的应用中,信号量的作用又该如何体现呢?比如有个 30 人的电脑机房,我们就可以创建信号量
的初始化值是 30,表示 30 个可用资源,不理解的初学者表示信号量还有初始值?是的,信号量说白了就
是共享资源的数量。 另外我们要求一个同学使用一台电脑,这样每有一个同学使用一台电脑,那么信号量
的数值就减一,直到 30 台电脑都被占用,此时信号量的数值就是 0。 如果此时还有几个同学没有电脑可
以使用,那么这几个同学就得等待,直到有同学离开,有一个同学离开,那么信号量的数值就加 1,有两
个就加 2,依次类推。刚才没有电脑用的同学此时就有电脑可以用了,有几个同学用,信号量就减几,直
到再次没有电脑可以用,这么一个过程就是使用信号量来管理共享资源的过程。
平时使用信号量主要实现以下两个功能:
两个任务或者中断函数跟任务之间的同步功能,这个和上章节讲解的事件标志组是类似的。其实就是
共享资源为 1 的时候。
多个共享资源的管理,就像上面举的机房上机的例子。
RTX 任务间信号量的实现

运行条件:
创建 2 个任务 Task1 和 Task2。
创建信号量可用资源为 1。
运行过程描述如下:
任务 Task1 运行过程中调用函数 os_sem_wait 获取信号量资源,如果信号量没有被任务 Task2 占用,
Task1 将直接获取资源。 如果信号被 Task2 占用,任务 Task1 将由运行态转到挂起状态,等待资源
可用。一旦获取了资源并使用完毕后会通过函数 os_sem_send 释放掉资源。
任务 Task2 运行过程中调用函数 os_sem_wait 获取信号量资源,如果信号量没有被任务 Task2 占用,
Task1 将直接获取资源。 如果信号被 Task2 占用,任务 Task1 将由运行态转到挂起状态,等待资源
可以。一旦获取了资源并使用完毕后会通过函数 os_sem_send 释放掉资源。
上面就是一个简单 RTX 任务间信号量的使用过程。
RTX 中断方式信号量的实现
RTX 中断方式信号量的实现是指中断函数和 RTX 任务之间使用信号量。 信号量的中断方式主要是用
于实现任务同步,与上个章节讲解事件标志组中断方式是一样的。
下面我们通过如下的框图来说明一下 RTX 中断方式信号量的实现,让大家有一个形象的认识。

运行条件:
创建 1 个任务 Task1 和一个串口接收中断。
信号量的初始值为 0,串口中断调用函数 isr_sem_send 释放信号量,任务 Task1 调用函数
os_sem_wait 获取信号量资源。
运行过程描述如下:
任务 Task1 运行过程中调用函数 os_sem_wait,由于信号量的初始值是 0,没有信号量资源可用,任
务 Task1 由运行态进入到挂起态。
Task1 挂起的情况下,串口接收到数据进入到了串口中断服务程序,在串口中断服务程序中调用函数
isr_sem_send 释放信号量资源,信号量数值加 1,此时信号量计数值为 1,任务 Task1 由挂起态进
入到就绪态,在调度器的作用下由就绪态又进入到运行态,任务 Task1 获得信号量后,信号量数值减
1,此时信号量计数值又变成了 0。
再次循环执行时,任务 Task1 调用函数 os_sem_wait 由于没有资源可用再次进入到挂起态,等待串
口释放信号量资源,如此往复循环。
上面就是一个简单 RTX 中断方式信号量同步过程。 实际应用中,中断方式的消息机制切记注意以下四个个
问题:
中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应。
实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在
任务中实现消息处理,这样可以有效的保证中断服务程序的实时响应。同时此任务也需要设置为高优
先级,以便退出中断函数后任务可以得到及时执行。
中断服务程序中一定要调用专用于中断的信号量设置函数 isr_sem_send。
在 RTX 操作系统中实现中断函数和裸机编程是一样的。
另外强烈推荐用户将 Cortex-M3 内核的 STM32F103 和 Cortex-M4 内核的 STM32F407,429 的
NVIC 优先级分组设置为 4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断
优先级的管理将非常方便。
用户要在 RTX 多任务开启前就设置好优先级分组,一旦设置好切记不可再修改。
信号量 API 函数
使用如下 4 个函数可以实现 RTX 的信号量:
os_sem_init
os_sem_send
isr_sem_send
os_sem_wait

函数 os_sem_init
函数原型:
void os_sem_init (
OS_ID semaphore, /* os_sem 类型变量 */
U16 token_count ); /* 信号量初始值 */
函数描述:
函数 os_sem_init 用于信号量的初始化并设置初始值
第 1 个参数填写数据类型为 OS_SEM 的变量,同时也作为 ID 标识
第 2 个参数是信号量初始值,也就是可用资源个数。
使用举例:

细心的读者可能发现,上面的初始化函数为什么不是这么写:os_sem_init(semaphore, 0),而是在变量
semaphore 前面加一个取地址符&,实际上这两种写法都是可以的,RTX 的手册里面默认都是前面加上
个取地址符,大家使用的时候也可以都加上,方便区分。
为什么两种写法都可以呢,因为 OS_SEM 是这么定义的:typedef U32 OS_SEM[2],对应上面的函
数举例就是 U32 semaphore[2],定义了一个 32 位数组,数组里面有两个元素。 所以 os_sem_init 的第
一个参数填 semaphore 或者&semaphore 都是这个数组的首地址。
还有就是,明明函数的第一个参数是OS_ID类型,为什么我们要定义一个OS_SEM类型的呢?这里是因为OS_ID是void *类型的,我是怎么知道要使用OS_SEM类型来初始化这个函数的呢?手册这样告诉我的:

函数 os_sem_send
函数原型:
OS_RESULT os_sem_send (
OS_ID semaphore ); /* OS_SEM 类型变量 */
函数描述:
函数 os_sem_send 用于释放信号量,调用后信号量计数值加 1。
第 1 个参数参数填写数据类型为 OS_SEM 的变量,同时也作为 ID 标识。
返回值永远是 OS_R_OK。
使用这个函数要注意以下问题:
1. 使用此函数前一定要调用函数 os_sem_init 进行初始化。

函数 isr_sem_send
函数原型:
void isr_sem_send (
OS_ID semaphore ); /* OS_SEM 类型变量 */
函数描述:
函数 isr_sem_send 用于释放信号量,调用后信号量计数值加 1。
第 1 个参数参数填写数据类型为 OS_SEM 的变量,同时也作为 ID 标识。
使用这个函数要注意以下问题:
1. 使用此函数前一定要调用函数 os_sem_init 进行初始化。

函数 os_sem_wait
函数原型:
OS_RESULT os_sem_wait (
OS_ID semaphore, /* OS_SEM 类型变量 */
U16 timeout ); /* 超时时间设置 */
函数描述:
函数 os_sem_wait 用于获取信号量,如果当前的信号量计数值大于 0,那么调用函数 os_sem_wait 后可
以成功获取信号量,并将信号量的计数值减 1。如果信号量计数值等于 0,调用此函数的任务将由运行态
转到挂起态,等待信号量资源可用,也就是等待信号量计数值大于 0。
第 1 个参数参数填写数据类型为 OS_SEM 的变量,同时也作为 ID 标识。
第 2 个参数表示设置的等待时间,范围 0-0xFFFF,当参数设置为 0-0xFFFE 时,表示等待这么多个
时钟节拍,参数设置为 0xFFFF 时表示无限等待直到有信号量资源可用。
函数返回 OS_R_SEM 表示函数设置的超时时间范围内收到信号量可用资源。
函数返回 OS_R_TMO 表示超时。
函数返回 OS_R_OK 表示无需等待,立即获得可用信号量资源。
使用这个函数要注意以下问题:
1. 使用此函数前一定要调用函数 os_sem_init 进行初始化。
使用举例:

代码练习场:



这里的信号量初始化为0,按键一下就发送一次,发送完毕并接收之后,就又变成了0.
串口打印:

RTX——第14章 信号量的更多相关文章
- 【二代示波器教程】第14章 uCOS-III操作系统版本二代示波器实现
第14章 uCOS-III操作系统版本二代示波器实现 本章教程为大家讲解uCOS-III操作系统版本的二代示波器实现.主要讲解RTOS设计框架,即各个任务实现的功能,任务间的通信方案选择,任 ...
- 【RL-TCPnet网络教程】第14章 RL-TCPnet之TCP客户端
第14章 RL-TCPnet之TCP客户端 本章节为大家讲解RL-TCPnet的TCP客户端实现,学习本章节前,务必要优先学习第12章TCP传输控制协议基础知识.有了这些基础知识之后,再搞本 ...
- Java核心技术卷一基础知识-第14章-多线程-读书笔记
第 14 章 多线程 本章内容: * 什么是线程 * 中断线程 * 线程状态 * 线程属性 * 同步 * 阻塞队列 * 线程安全的集合 * Collable与Future * 执行器 * 同步器 * ...
- ASM:《X86汇编语言-从实模式到保护模式》第14章:保护模式下的特权保护和任务概述
★PART1:32位保护模式下任务的隔离和特权级保护 这一章是全书的重点之一,这一张必须要理解特权级(包括CPL,RPL和DPL的含义)是什么,调用门的使用,还有LDT和TSS的工作原理(15章着重 ...
- 敏捷软件开发:原则、模式与实践——第14章 使用UML
第14章 使用UML 在探索UML的细节之前,我们应该先讲讲何时以及为何使用它.UML的误用和滥用已经对软件项目造成了太多的危害. 14.1 为什么建模 建模就是为了弄清楚某些东西是否可行.当模型比要 ...
- Linux就这个范儿 第14章 身在江湖
Linux就这个范儿 第14章 身在江湖 “有人的地方就有江湖”,如今的计算机世界就像一个“江湖”.且不说冠希哥有多么无奈,把微博当QQ的局长有多么失败,就说如此平凡的你我什么时候就成了任人摆布的羔羊 ...
- php大力力 [016节] 兄弟连高洛峰php教程(2014年 14章数据库章节列表)
2015-08-25 php大力力016 兄弟连高洛峰php教程(2014年 14章数据库章节列表) [2014]兄弟连高洛峰 PHP教程14.1.1 复习数据库 15:58 [2014]兄弟连高洛 ...
- JavaScript高级程序设计(第三版)学习笔记13、14章
第13章,事件 事件冒泡 IE的事件叫做事件冒泡:由具体到不具体 <!DOCTYPE html> <html> <head> <title>E ...
- 《Android开发艺术探索》读书笔记 (13) 第13章 综合技术、第14章 JNI和NDK编程、第15章 Android性能优化
第13章 综合技术 13.1 使用CrashHandler来获取应用的Crash信息 (1)应用发生Crash在所难免,但是如何采集crash信息以供后续开发处理这类问题呢?利用Thread类的set ...
随机推荐
- plsql 表数据中文显示乱码(配置环境变量)
plsql 表数据中文显示乱码(配置环境变量) CreateTime--2018年4月23日19:32:37 Author:Marydon 1.情景再现 2.解决方案 配置环境变量 变量名:NLS ...
- 一段测试try...catch运行时间的代码
public class Test2 { private static int test() { int i=1; try { i=2; ...
- Linux 系统文件类型
在Linux中只有一下7种文件类型 1.普通文件(-表示,可用ls -l查看) 2.目录(d)[在linux中,任何东西都被看成文件,外设备也看成文件,注意是任何东西] 3.字符设备文件(c) 4.块 ...
- DevExpress添加Winform窗体到DockPanel
在使用DevExpress过程中,原先已经创建好的导航窗体,如何添加到DockPanel中进行展示? FormX frmX = new FormX(); frmX.Show(this.DockPane ...
- CentOS6.3的VNC--远程桌面
2G内存的服务器开启Gnome图形化界面应该没什么问题.1G还有512M的内存的就不敢开启了,现在内存正常状态就已经60%左右了. CentOS6.3服务器,Gnome图形化界面按照阿里官方步骤:一. ...
- 错误号:1364 错误信息:Field 'platId' doesn't have a default value
1. 错误描写叙述 错误号:1364 错误信息:Field 'platId' doesn't have a default value insert into `use`.`t_platform_sc ...
- tomcat部署war包访问显示404
在eclipse导出的maven项目war包,放到tomcat下启动,顺利启动且无报错,但是浏览器访问该项目时显示404 原因:未在server.xml中配置这几个项目,导致服务器查找不到 解决方法: ...
- Linux目录结构及解释(附图)
___/bin (binary二进制) 常用Linux命令 ___/boot 存放着启动Linux时使用的一些核心文件,包括一些链接文件以及镜像文件 ___/cdrom 这个目录在你刚刚安装系统的时候 ...
- 你的Android不好用,都是因为这几点原因
Android早已是全球最大.用户最多的移动操作系统,不过它离全球最好用还差得很远. 大家随手就能举出些曾经历过的糟心体验,如手机卡顿!电量不禁用!广告弹窗老是出现!不过很少有人会追根寻底的去问为何如 ...
- 百度UEditor富文本编辑器去除过滤div等标签
将设计排版好的页面html代码上传到数据库,再读取出来的时候发现所有的div都被替换成了p标签. 解决方法: 首先在ueditor.all.js文件内搜索allowDivTransToP,找到如下的代 ...