注:本文摘自韦东山《FreeRTOS完全开发手册》,如有侵权请告知
同步与互斥的概念:
-
同步: A等待B做完某件事
-
互斥: 某一资源同一时间仅能有一个用户访问
-
RTOS同步与互斥的方式: 任务通知(task notification)、队列(queue)、事件组(event group)、信号量(semaphoe)、互斥量(mutex)等。
二、信号量
信号量只能传递状态,不能传递具体的信息
2.1 信号量的特性
-
信号:起通知作用
-
量:还可以用来表示资源的数
- 当"量"没有限制时,它就是"计数型信号量"(Counting Semaphores)
- 当"量"只有0、1两个取值时,它就是"二进制信号量"(Binary Semaphores)
-
支持的动作:"give"给出资源,计数值加1;"take"获得资源,计数值减1
2.2 信号量跟队列的区别
队列 | 信号量 |
---|---|
可以容纳多个数据, 创建队列时有2部分内存: 队列结构体、存储数据的空间 | 只有计数值,无法容纳其他数据。 创建信号量时,只需要分配信号量结构体 |
生产者:没有空间存入数据时可以阻塞 | 生产者:不阻塞,计数值已经达到最大时 返回失败 |
消费者:没有数据时可以阻塞 | 消费者:没有资源时可以阻塞 |
2.3 信号量函数
使用信号量时,先创建、然后去添加资源、获得资源。使用句柄来表示一个信号量。
2.3.1 创建信号量
- 二进制信号量
/* 创建二进制信号量
* 返回值: 返回句柄,非NULL表示成功
*/
SemaphoreHandle_t xSemaphoreCreateBinary(void);
/* 创建一个二进制信号量
* 此函数无需动态分配内存,所以需要先有一个StaticSemaphore_t结构体,并传入它的指针
* 返回值: 返回句柄,非NULL表示成功
*/
SemaphoreHandle_t xSemaphoreCreateBinaryStatic(StaticSemaphore_t *pxSemaphoreBuffer );
- 计数型信号量
/* 创建一个计数型信号量
* uxMaxCount: 最大计数值
* uxInitialCount: 初始计数值
* 返回值: 返回句柄,非NULL表示成功
*/
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount);
/* 创建一个计数型信号量
* uxMaxCount: 最大计数值
* uxInitialCount: 初始计数值
* pxSemaphoreBuffer: StaticSemaphore_t结构体指针
* 返回值: 返回句柄,非NULL表示成功
*/
SemaphoreHandle_t xSemaphoreCreateCountingStatic(UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount,
StaticSemaphore_t
*pxSemaphoreBuffer );
2.3.2 删除信号量
对于动态创建的信号量,不再需要它们时,可以删除它们以回收内存
/* xSemaphore: 信号量句柄,你要删除哪个信号量 */
void vSemaphoreDelete(SemaphoreHandle_t xSemaphore );
2.3.3 give/take
- give释放信号量
/* 释放信号量
* xSemaphore:信号量句柄,释放哪个信号量
* 返回值:pdTRUE表示成功,如果二进制信量的计数值已经是最大值,调用此函数则返回失败;
*/
BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore );
/* 释放信号量
* xSemaphore:信号量句柄,释放哪个信号量
* pxHigherPriorityTaskWoken:如果释放信号量导致更高优先级的任务变为了就绪态,
* 则*pxHigherPriorityTaskWoken = pdTRUE
* 返回值:pdTRUE表示成功,如果二进制信量的计数值已经是最大值,调用此函数则返回失败;
*/
BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken);
- take获取信号量
/* 获取信号量
* xSemaphore:信号量句柄,获取哪个信号量
* xTicksToWait:0:不阻塞,马上返回
* portMAX_DELAY: 一直阻塞直到成功
* 其他值: 阻塞的Tick个数
* 返回值:pdTRUE表示成功
*/
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);
/* 获取信号量
* xSemaphore:信号量句柄,获取哪个信号量
* pxHigherPriorityTaskWoken:如果获取信号量导致更高优先级的任务变为了就绪态,
* 则*pxHigherPriorityTaskWoken = pdTRUE
* 返回值:pdTRUE表示成功
*/
BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken);