本节需要掌握以下内容:
1,信号量的简介(了解)
2,二值信号量(熟悉)
3,二值信号量实验(掌握)
4,计数型信号量(熟悉)
5,计数型信号量实验(掌握)
6,优先级翻转简介(熟悉)
7,优先级翻转实验(掌握)
8,互斥信号量(熟悉)
9,互斥信号量实验(掌握)
一、信号量的简介(了解)
1.1 信号量的概念
信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问
举个栗子:假设有一个人需要在停车场停车。
1、首先判断停车场是否还有空车位(判断信号量是否有资源);
2、停车场正好又空位(信号量又资源),那么就可以直接将车开入空位进行停车(获取信号量成功);
3、停车场已经没有空位了(信号量没有资源),那么这个人可以选择不停车(获取信号量失败);也可以选择等待(任务阻塞)其他人将车开出停车场(释放信号量资源),然后再将车停入空车位。
空车位 : 信号量资源数(计数值)
让出占用车位 : 释放信号量(计数值++)
占用车位 : 获取信号量(计数值 --)
当数值大于0,代表有信号量资源
当释放信号量,信号量计数值(资源数)加一
当获取信号量,信号量计数值(资源数)减一
信号量:用于传递状态
信号量的计数值都有限制:限定最大值。
如果最大值被限定为1,那么它就是二值信号量;
如果最大值不是1,那么它就是计数型信号量。
1.2 队列与信号量的对比
队列 | 信号量 |
可以容纳多个数据; 创建队列有两部分内存:队列结构体+队列项存储空间 | 仅存放计数值,无法存放其他数据; 创建信号量,只需分配信号量结构体 |
写入队列:当队列满时,可阻塞; | 释放信号量:不可阻塞,计数值++, 当计数值为最大值时,返回失败 |
读取队列:当队列为空时,可阻塞; | 获取信号量:计数值--, 当没有资源时,可阻塞 |
二、二值信号量(熟悉)
2.1 二值信号量相关概念
二值信号量的本质是一个队列长度为1的队列,该队列就只有空 和 满两种情况,这就是二值。
二值信号量通常用于互斥访问或者任务同步,与互斥信号量比较类似,但是二值信号量可能会导致优先级翻转的问题,所以二值信号量更适合用于同步!
2.2 二值信号量相关API函数(熟悉)
使用二值信号量的过程:创建二值信号量->释放二值信号量->获取二值信号量
函数 | 描述 |
xSemaphoreCreateBinary() | 使用动态方式创建二值信号量 |
xSemaphoreCreateBinaryStatic() | 使用静态方式创建二值信号量 |
xSemaphoreGive() | 释放信号量 |
xSemaphoreGiveFromISR() | 在中断中释放信号量 |
xSemaphoreTake() | 获取信号量 |
xSemaphoreTakeFromISR() | 在中断中获取信号量 |
创建方式仅介绍动态创建的方式。
2.2.1 创建二值信号量函数:SemaphoreHandle_t xSemaphoreCreateBinary( void )
返回值 | 描述 |
NULL | 创建失败 |
其他值 | 创建成功返回二值信号量的句柄 |
2.2.2 释放二值信号量函数:BaseType_t xSemaphoreGive( xSemaphore )
形参 | 描述 |
xSemaphore | 要释放的信号量句柄 |
返回值 | 描述 |
pdPASS | 释放信号量成功 |
errQUEUE_FULL | 释放信号量失败 |
2.2.3 获取二值信号量函数:BaseType_t xSemaphoreTake( xSemaphore, xBlockTime )
形参 | 描述 |
xSemaphore | 要获取的信号量句柄 |
xBlockTime | 阻塞时间 |
返回值 | 描述 |
pdTRUE | 获取信号量成功 |
pdFALSE | 超时,获取信号量失败 |
三、二值信号量实验(掌握)
3.1、实验目的:
学习 FreeRTOS 的二值信号量相关API函数的使用
3.2、实验设计:
将设计三个任务:start_task、task1、task2
三个任务的功能如下:
- start_task:用来创建task1和task2任务
- task1:用于按键扫描,当检测到按键KEY0被按下时,释放二值信号量
- task2:获取二值信号量,当成功获取后打印提示信息
3.3 实验代码
demo.c
空格不够了,明日再更!
四、计数型信号量(熟悉)
4.1 计数型信号量相关概念
计数型信号量相当于队列长度大于1的队列,因此计数型信号量能够容纳多个资源,这在计数型信号量被创建的时候确定的。
计数型信号量适用场合:
事件计数:当每次事件发生后,在事件处理函数中释放技术型信号量(计数值+1),其它任务会获取计数型信号量(计数值-1),这种场合一般在创建时将初始计数值设置为0
资源管理:信号量表示有效的资源数目。任务必须先获取信号量(信号量计数值-1),才能获取资源控制权。当计数值减为零时表示没有资源。当任务使用完资源后,必须释放信号量(信号量计数值+1)。信号量创建时计数值应等于最大资源数目。
4.2 使用计数型信号量相关API函数(熟悉)
使用计数型信号量的过程:创建计数型信号量->释放信号量->获取信号量
函数 | 描述 |
xSemaphoreCreateCounting() | 使用动态方法创建计数型信号量。 |
xSemaphoreCreateCountingStatic() | 使用静态方法创建计数型信号量 |
uxSemaphoreGetCount() | 获取信号量的计数值 |
计数型信号量的释放和获取与二值信号量相同 !此处也仅介绍动态方法创建计数型信号量。
4.2.1 计数型信号量创建API函数
#define xSemaphoreCreateCounting( uxMaxCount , uxInitialCount ) \
xQueueCreateCountingSemaphore( ( uxMaxCount ) , ( uxInitialCount ) )
此函数用于创建一个计数型信号量 。
形参 | 描述 |
uxMaxCount | 计数值的最大值限定 |
uxInitialCount | 计数值的初始值 |
返回值 | 描述 |
NULL | 创建失败 |
其他值 | 创建成功返回计数型信号量的句柄 |
4.2.2 获取信号量的计数值
#define uxSemaphoreGetCount( xSemaphore ) \
uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
此函数用于获取信号量当前计数值大小
形参 | 描述 |
xSemaphore | 信号量句柄 |
返回值 | 描述 |
整数 | 当前信号量的计数值大小 |
五、计数型信号量实验(掌握)
5.1、实验目的:
学习 FreeRTOS 的计数型信号量相关API函数的使用
5.2、实验设计:
将设计三个任务:start_task、task1、task2
三个任务的功能如下:
- start_task:用来创建task1和task2任务
- task1:用于按键扫描,当检测到按键KEY0被按下时,释放计数型信号量
- task2:每过一秒获取一次计数型信号量,当成功获取后打印信号量计数值
5.3 实验代码
demo.c
六、优先级翻转简介(熟悉)
优先级翻转:高优先级的任务反而慢执行,低优先级的任务反而优先执行。