目录
特点预览
二值信号量:只有空和满两种状态;
计数信号量:释放信号量时增加信号量的计数值(即个数);
互斥信号量:具有优先级继承的二值信号量,能降低任务优先级翻转的情况;
递归互斥信号量:同一个任务中可以无限次获取递归互斥信号量,中途不需要释放。任务获取多少次,就要释放多少次。
其中:二值、计数、互斥信号量的释放与获取函数相同。
一、信号量
在裸机编程中常用一个变量来标记某些事件的发生即常说的标志位,在FreeRTOS中的信号量与其类似。信号量是一种实现任务间通信的机制,可以实现任务之间同步或临界资源互斥访问,常用于协助一组相互竞争的任务来访问临界资源。信号量是一个非负整数,所有获取它的任务都会将该整数减一,当该整数为0是,所有试图获取它的任务将进入阻塞状态。通常一个信号量的计数值用于对应有效的资源数,表示剩下的可被占用的互斥资源数。其值分两种情况:
0: 表示没有积累下来的释放信号量操作,且有可能在此信号量上阻塞的任务;
正值:表示有一个或多个释放信号量。
(释放信号量就是向信号量写入内容的意思)
信号量句柄类型宏定义:
typedef QueueHandle_t SemaphoreHandle_t; //动态
typedef StaticQueue_t StaticSemaphore_t; //静态
二、二值信号量
二值信号量其实就是一个只有一个队列项的队列,这个队列非空即满,两种状态就是二值。二值信号量通常用于互斥访问或同步。相较于互斥信号量,二值信号量没有优先级继承以至容易造成任务优先级翻转(低优先级任务先于高优先级任务执行),因此二值信号量更适合用于同步。
当信号量被获取之后信号量变为空即无效,需要重新释放信号量任务才能成功获取。
使用二值信号量需要将该宏定义为1,在FreeRTOS.h文件中:
#define configSUPPORT_DYNAMIC_ALLOCATION 1
相关的函数都是宏定义,在semphr.h中。
1、创建二值信号量
(1)动态创建
/*函数*/
SemaphoreHandle_t xSemaphoreCreateBinary()
/*
*返回值:
*创建失败NULL,创建成功返回信号量句柄。
*/
/*函数的宏定义*/
#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, //长度1
semSEMAPHORE_QUEUE_ITEM_LENGTH, //0
queueQUEUE_TYPE_BINARY_SEMAPHORE )
(2)静态创建
/*函数原型*/
SemaphoreHandle_t xSemaphoreCreateBinaryStatic(StaticSemaphore_t pxStaticSemaphore )
/*
*参数:
*pxStaticSemaphore:指向StaticSemaphore_t类型的变量,用来保存信号量结构体。
*返回值:
*创建失败NULL,创建成功返回信号量句柄。
*/
/*函数的宏定义*/
#define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) \
xQueueGenericCreateStatic( ( UBaseType_t ) 1,
semSEMAPHORE_QUEUE_ITEM_LENGTH,
NULL,
pxStaticSemaphore,
queueQUEUE_TYPE_BINARY_SEMAPHORE )
2、释放信号量
(1)任务级
/*函数原型*/
BaseType_t xSemaphoreGive( xSemaphore )
/*
*参数:
*xSemaphore: 信号量句柄
*返回值:
*pdPASS: 释放信号量成功
*errQUEUE_FULL:释放信号量失败
*/
/*函数的宏定义*/
#define xSemaphoreGive( xSemaphore ) \
xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ),
NULL,
semGIVE_BLOCK_TIME,
queueSEND_TO_BACK )
(2)中断级
/*函数原型*/
BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore,
BaseType_t * pxHigherPriorityTaskWoken )
/*
*参数:
*xSemaphore : 信号量句柄
*pxHigherPriorityTaskWoken:标记退出函数是否进行任务切换,只需提供变量保存即可,当该值为pdTRUE时
* 需要进行任务切换。
*返回值:
*pdPASS: 释放信号量成功
*errQUEUE_FULL: 释放信号量失败
*/
/*函数宏定义*/
#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) \
xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ),
( pxHigherPriorityTaskWoken ) )
3、获取信号量
(1)任务级
/*函数原型*/
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xBlockTime )
/*
*参数:
*xSemaphore: 信号量句柄
*xBlockTime: 阻塞时间
*返回值:
*pdPASS: 获取信号量成功
*pdFALSE: 超时,获取信号量失败
*/
/*函数宏定义*/
#define xSemaphoreTake( xSemaphore, xBlockTime ) \
xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
(2)中断级
/*函数原型*/
BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,
BaseType_t * pxHigherPriorityTaskWoken )
/*
*参数:
*xSemaphore : 信号量句柄
*pxHigherPriorityTaskWoken:标记退出函数是否进行任务切换,只需提供变量保存即可,当该值为pdTRUE时
* 要进行任务切换。
*返回值:
*pdPASS: 获取信号量成功
*pdFALSE: 获取信号量失败
*/
/*函数宏定义*/
#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) \
xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ),
NULL,
( pxHigherPriorityTaskWoken ) )
三、计数型信号量
二值信号量相当于长度为1的队列,计数型信号量就是长度大于1的队列。释放信号量时增加信号量的计数值(即个数),获取信号量时信号量计数值减1。创建时初始计数值为0。
1、创建计数型信号量
(1)动态方法
/*函数原型*/
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount )
/*
参数:
*uxMaxCount: 计数信号量最大计数值(信号量个数)
*uxInitialCount:计数信号量初始值(初始有效信号量个数)
*返回值: 创建失败NULL,创建成功返回信号量句柄。
*/
/*函数宏定义*/
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) \
xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
(2)静态方法
/*函数原型*/
SemaphoreHandle_t xSemaphoreCreateCountingStatic(UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount,
StaticSemaphore_t * pxSemaphoreBuffer )
/*
*参数:
*uxMaxCount: 计数信号量最大计数值(信号量个数)
*uxInitialCount: 计数信号量初始值(初始有效信号量个数)
*pxSemaphoreBuffer: 指向StaticSemaphore_t类型的变量,用来保存信号量结构体。
*返回值: 创建失败NULL,创建成功返回信号量句柄。
*/
/*函数宏定义*/
#define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) \
xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ),
( uxInitialCount ),
( pxSemaphoreBuffer ) )
2、释放和获取计数信号量(与二值的相同)
释放与获取函数与二值信号量的相同。
四、互斥信号量
互斥信号量就是具有优先级继承的二值信号量,具有优先级继承能够一定程度降低任务优先级翻转的情况。(当多个不同优先级的任务需要获取同一个二值信号量时容易出现优先级翻转情况,使用互斥信号量时,高优先级的任务会将低优先级的任务的优先级提升到与自己同级的优先级,这就是继承。)互斥信号量不能用于中断服务函数中,原因:
(1)互斥信号量具有优先级继承,不能用于中断服务函数;
(2)中断服务函数不能因为要等待互斥信号量而设置阻塞时间进入阻塞。
1、创建互斥信号量
(1)动态方法
/*函数原型*/
SemaphoreHandle_t xSemaphoreCreateMutex()
/*
*参数: 无
*返回值:创建失败NULL,创建成功返回信号量句柄。
*/
/*函数宏定义*/
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
(2)静态方法
/*函数原型*/
SemaphoreHandle_t xSemaphoreCreateMutexStatic(StaticSemaphore_t * pxMutexBuffer )
/*
*参数:
*pxMutexBuffer:指向StaticSemaphore_t类型的变量,用来保存信号量结构体。
*返回值: 创建失败NULL,创建成功返回信号量句柄。
*/
/*函数宏定义*/
#define xSemaphoreCreateMutexStatic( pxMutexBuffer ) \
xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) )
2、释放和获取互斥信号量(与二值的相同)
释放与获取函数与二值信号量的相同。
五、递归互斥信号量
递归互斥信号量可以看是一种特殊的互斥信号量,已经获取了信号量的任务就不能再次获取这个互斥量,但是递归互斥信号量不同,已经获取了递归互斥信号量的任务可以再次获取这个递归互斥信号量,次数不限。也就是在同一个任务中可以无限次获取递归互斥信号量,中途不需要释放,而互斥信号量获取一次后就失效,需要再次释放才有效。注意:任务获取多少次递归互斥信号量,就要释放多少次递归信号量。
1、创建递归互斥信号量
(1)动态方法
/*函数原型*/
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )
/*
*参数: 无
*返回值:创建失败NULL,创建成功返回信号量句柄。
*/
/*函数宏定义*/
#define xSemaphoreCreateRecursiveMutex() \
xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )
(2)静态方法
/*函数原型*/
SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )
/*
*参数:
*pxMutexBuffer:指向StaticSemaphore_t类型的变量,用来保存信号量结构体。
*返回值: 创建失败NULL,创建成功返回信号量句柄。
*/
/*函数宏定义*/
#define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) \
xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore )
2、释放递归互斥信号量
/*函数原型*/
xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex )
/*
*参数:
*xMutex: 信号量句柄
*返回值:
*pdPASS: 释放信号量成功
*pdFAIL: 释放信号量失败
*/
/*函数宏定义*/
#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) )
3、获取递归互斥信号量
/*函数原型*/
xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex,
TickType_t xBlockTime
);
/*
*参数:
*xMutex: 信号量句柄
*xBlockTime:阻塞时间
*返回值:
*pdPASS: 获取信号量成功
*pdFAIL: 获取信号量失败
*/
/*函数宏定义*/
#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) \
xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )