FreeRTOS 二值信号量,互斥信号量

本章节讲解 FreeRTOS 任务间的同步和资源共享机制,二值信号量。 二值信号量是计数信号量的一种特殊形式,即共享资源为 1 的情况。

FreeRTOS 分别提供了二值信号量和计数信号量,其中二值信号量可以理解成计数
信号量的一种特殊形式,即初始化为仅有一个资源可以使用,只不过 FreeRTOS 对这两种都提供了 API
函数,而像 RTX,uCOS-II 和 III 是仅提供了一个信号量功能,设置不同的初始值就可以分别实现二值信
号量和计数信号量。 当然,FreeRTOS 使用计数信号量也能够实现同样的效果。 另外,为什么叫二值信号
量呢?因为信号量资源被获取了,信号量值就是 0,信号量资源被释放,信号量值就是 1,把这种只有 0
和 1 两种情况的信号量称之为二值信号量。

函数 xSemaphoreCreateBinary
函数原型:
SemaphoreHandle_t xSemaphoreCreateBinary(void)
函数描述:
函数 xSemaphoreCreateBinary 用于创建二值信号量。
? 返回值,如果创建成功会返回二值信号量的句柄,如果由于 FreeRTOSConfig.h 文件中 heap 大小不
足,无法为此二值信号量提供所需的空间会返回 NULL。

FreeRTOS 重要的资源共享机制---互斥信号量(Mutex,即 Mutual Exclusion 的缩写)。
注意,建议初学者学习完前两个信号量后再学习本章节的互斥信号量。

互斥信号量的主要作用是对资源实现互斥访问,使用二值信号量也可以实现互斥访问的功能,不过互
斥信号量与二值信号量有区别。 下面我们先举一个通过二值信号量实现资源独享,即互斥访问的例子,让
大家有一个形象的认识,进而引出要讲解的互斥信号量。
运行条件:
? 让两个任务 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 得到互斥资源,
从而可以继续执行。

FreeRTOS 互斥信号量的实现
FreeRTOS 互斥信号量是怎么实现的呢?其实相对于二值信号量,互斥信号量就是解决了一下优先级
翻转的问题。 下面我们通过如下的框图来说明一下 FreeRTOS 互斥信号量的实现,让大家有一个形象的认识。

运行条件:
? 创建 2 个任务 Task1 和 Task2,优先级分别为 1 和 3,也就是任务 Task2 的优先级最高。
? 任务 Task1 和 Task2 互斥访问串口打印 printf。
? 使用 FreeRTOS 的互斥信号量实现串口打印 printf 的互斥访问。
运行过程描述如下:

? 低优先级任务 Task1 执行过程中先获得互斥资源 printf 的执行。 此时任务 Task2 抢占了任务 Task1
的执行,任务 Task1 被挂起。 任务 Task2 得到执行。
? 任务 Task2 执行过程中也需要调用互斥资源,但是发现任务 Task1 正在访问,此时任务 Task1 的优
先级会被提升到与 Task2 同一个优先级,也就是优先级 3,这个就是所谓的优先级继承(Priority
inheritance),这样就有效地防止了优先级翻转问题。 任务 Task2 被挂起,任务 Task1 有新的优先
级继续执行。
? 任务 Task1 执行完毕并释放互斥资源后,优先级恢复到原来的水平。 由于互斥资源可以使用,任务
Task2 获得互斥资源后开始执行。

FreeRTOS 中断方式互斥信号量的实现
互斥信号量仅支持用在 FreeRTOS 的任务中,中断函数中不可使用。

互斥信号量 API 函数
函数 xSemaphoreCreateMutex
函数原型:
SemaphoreHandle_t xSemaphoreCreateMutex( void )
函数描述:
函数 xSemaphoreCreateMutex 用于创建互斥信号量。
? 返回值,如果创建成功会返回互斥信号量的句柄,如果由于 FreeRTOSConfig.h 文件中 heap 大小不
足,无法为此互斥信号量提供所需的空间会返回 NULL。

使用这个函数要注意以下问题:
1. 此函数是基于函数 xQueueCreateMutex 实现的:
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
函数 xQueueCreateMutex 的实现是基于消息队列函数 xQueueGenericCreate 实现的。
2. 使用此函数要在 FreeRTOSConfig.h 文件中使能宏定义:
#define configUSE_MUTEXES 1

互斥信号量, xSemaphoreTake 和 xSemaphoreGive 一定要成对的调用 

时间: 2024-10-03 23:15:49

FreeRTOS 二值信号量,互斥信号量的相关文章

Freertos-事件标志组,消息队列,信号量,二值信号量,互斥信号量

任务间的通信和同步机制  在裸机编程时,使用全局变量的确比较方便,但是在加上 RTOS 后就是另一种情况了. 使用全局变量相比事件标志组主要有如下三个问题: 1.使用事件标志组可以让 RTOS 内核有效地管理任务,而全局变量是无法做到的,任务的超时等机制需要用户自己去实现.2.使用了全局变量就要防止多任务的访问冲突,而使用事件标志组则处理好了这个问题,用户无需担心.3.使用事件标志组可以有效地解决中断服务程序和任务之间的同步问题. 事件标志组:事件标志组是实现多任务同步的有效机制之一. 每创建一

FreeRTOS学习笔记——二值型信号量

1.前言 在嵌入式操作系统中二值型信号量是任务间.任务与中断间同步的重要手段.FreeRTOS的二值型信号量简单易用,下面结合一个具体例子说明FreeRTOS中的二值型信号量如何使用. [相关博文] [FreeRTOS STM32移植笔记] [FreeRTOS学习笔记--任务间使用队列同步数据] [如何在FreeRTOS下实现低功耗--MSP430F5438平台] [代码链接]--示例代码存于百度网盘 2.特别说明         二值型信号量的使用方法见图1所示,二值型信号量可以理解为任务与中

二值信号量和互斥锁到底有什么区别?

在说明之前我先抛出结论:互斥锁和二值信号量在使用上非常相似,但是互斥锁解决了优先级翻转的问题 假定我们现在有三个任务,task1,task2,task3,任务优先级task1最高,然后依次降低.我们知道在系统调度的时候当两个任务同时处于就绪态的时候,系统会优先执行优先级高的任务 好了,让我们来看两个案例 优先级翻转分析(使用信号量) 在例子中,我们使用pend()函数来表示获取信号量,用post()函数来表示释放信号量 如上图所示,过程分下面几步 1.一开始task3开始运行,先获取到信号量 2

16.信号量互斥编程

我们先来看一个例子.就是两个进程访问同一个文件,由于线程的先后,导致内容的异常.即是数据内容的混乱. Student1.c: #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> ? void main(){ ????//open file ????int fd = 0; ????fd = open("/home/wen",O

信号量互斥,王明学learn

信号量互斥 信号量(又名:信号灯)与其他进程间通信方式不大相同,主要用途是保护临界资源(进程互斥).进程可以根据它判定是否能够访问某些共享资源.除了用于访问控制外,还可用于进程同步. 一.信号量分类 二值信号灯:信号灯的值只能取0或1 计数信号灯:信号灯的值可以取任意非负值. 二.函数学习 2.1创建/打开信号量 2.1.1 函数名 semget 2.1.2 函数原形 int semget(key_t key,int nsems,int semflg); 2.1.3 函数功能 获取信号量集合标示

Linux 信号量互斥编程

所谓信号量,其实就是一个数字.内核给这个数字赋予一定的含义,让它等于不同的值时所表示的意义不同.这样就可以用它来标示某种资源是否正被使用.信号的分类其实挺多的,主要还是二值和计数器.这里讨论二值 现在有个文件,有两个进程要同时访问它.进程A 要往里面写入 "Math class is cancel",进程B 要往里面写入“English test”.正常情况下这两个信息会被完整的写入文件中.但是如果进程A写到"Math class" 就暂停,接着B进程就开始写“En

ucos2 事件 任务的通讯和同步 信号量 互斥量 消息邮箱 消息队列

这会想了想,在复习资料后,最后再做个核心代码分析 ucos中使用信号量.消息邮箱.消息队列,这些数据结构来作为通信中间媒介.这些数据结构会影响任务的程序流程,因此也叫做事件. 一.信号量 是进行任务通信的最基本事件 二值信号可以实现共享资源的独占,也叫互斥信号量. 注意:使用信号量的时候要,高优先级的任务等待接受信号量的时候,高优先级的任务在等待接受信号量的时候,如果低优先级的任务没有释放信号量,那就会一直等待下去,那低优先级的任务就没有机会运行了,系统就出现死机的状况了.   解决方法:加个超

第三季-第16课-信号量互斥编程

第16课-信号量互斥编程 16.1 公示栏问题(问题引入) 1. 问题描述 这里面我们举一个小例子.在一个班级里就有一个公示栏,A同学想写“数学课考试”,B同学想写“英语课取消”.但是有一个时间,A同学只写下了“数学课”三个字,没来得及写后面的内容就出去了,但是这个时候B同学来写下了“英语课取消”.这样让同学们看来就成了“数学课英语课取消”,给班级的其他同学造成了歧义. 这也就是我们说的同时访问一个资源,造成了,数据的混乱.若是有多个进程同时访问一个资源,同样会造成这个问题. 2. 问题程序化

ucos互斥信号量解决优先级反转问题

在可剥夺性的内核中,当任务以独占方式使用共享资源的时候,会出现低优先级任务高于高优先级任务运行的情况,这种情况叫做优先级反转,对于实时操作系统而言,这是一场灾难,下面我们来说说优先级反转的典型环境. 我们假设有三个任务a,b,c,a优先级高于b,b优先级高于c,a和c都需要访问一个共享资源s,保护该资源的信号量为互斥信号量, 假设当前任务c申请了信号量访问s,还没有释放,此时任务a开始运行,那么a就会剥夺c的运行而运行a,当a去访问资源s的时候,因为得不到信号量,所以必须释放以等待信号量,任务c