如图1所示,信号量目的
- 解决共享资源的访问问题。
- 处理实现任务-中断/任务-任务间的同步。问题(一个任务可继续执行的触发时机)
2,信号量分类
- 二值信号量:适合任务间的同步
- 数值信号量
- 互斥信号量:具有优先级继承机制,适合任务间对资源的互斥访问。
- 递归互斥信号量
3,特征
- 因为信号量阻塞的任务,信号量获取时,高优先级任务优先接触阻塞。
- 二值信号量是使用仅有1个队列项的队列实现的(是否是满)。
- 分为中断级别接口和应用级别接口。
4,相关API
//定义信号量的句柄类型(等同于队列句柄类型)
//队列句柄类型(typedef void * QueueHandle_t;)
typedef QueueHandle_t SemaphoreHandle_t;
#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( uint8_t ) 1U )
#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U )
#define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U )
/*
这个旧的vSemaphoreCreateBinary()宏现在被弃用,代之以xSemaphoreCreateBinary()函数。注意,
使用vSemaphoreCreateBinary()宏创建的二进制信号量是在这样一种状态下创建的,即对“take”信号量的第一个调用将通过,
而使用xSemaphoreCreateBinary()创建的二进制信号量是在这样一种状态下创建的,即信号量必须先“give”,然后才能“take”。
*/
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
#define vSemaphoreCreateBinary( xSemaphore ) \
{ \
//创建一个容量为1,队列项大小为0byte的 queueQUEUE_TYPE_BINARY_SEMAPHORE 类型动态队列
( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \
if( ( xSemaphore ) != NULL ) \
{ \
( void ) xSemaphoreGive( ( xSemaphore ) ); \
} \
}
#endif
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif
//创建一个新的二进制信号量实例,并返回一个句柄
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
//创建一个容量为1,队列项大小为0byte的 queueQUEUE_TYPE_BINARY_SEMAPHORE 类型队列
#define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif /* configSUPPORT_STATIC_ALLOCATION */
//宏获取一个信号量。这个信号量之前必须通过调用xSemaphoreCreateBinary()、xSemaphoreCreateMutex()或xsemaphorecreat()来创建。
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
//宏以递归方式获取或'take'互斥类型信号量。互斥锁之前必须使用对xSemaphoreCreateRecursiveMutex()的调用来创建;
#if( configUSE_RECURSIVE_MUTEXES == 1 )
#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )
#endif
//宏释放一个信号量。这个信号量之前必须通过调用xSemaphoreCreateBinary()、xSemaphoreCreateMutex()或xsemaphorecreat()来创建。
//并利用sSemaphoreTake()得到。这个宏不能从ISR中使用。参见xSemaphoreGiveFromISR(),了解可以从ISR中使用的替代方案。
#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
//递归释放或'give'互斥锁类型的信号量,互斥锁之前必须通过调用xSemaphoreCreateRecursiveMutex()来创建;
#if( configUSE_RECURSIVE_MUTEXES == 1 )
#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) )
#endif
//宏释放一个信号量。这个信号量之前必须通过调用xSemaphoreCreateBinary()或xsemaphorecreat()来创建。
//互斥类型信号量(使用调用xSemaphoreCreateMutex()创建的信号量)不能与这个宏一起使用。这个宏可以从ISR中使用。
#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) )
//宏从ISR获取信号量。这个信号量之前必须通过调用xSemaphoreCreateBinary()或xsemaphorecreat()来创建。
//互斥类型信号量(使用调用xSemaphoreCreateMutex()创建的信号量)不能与此宏一起使用。这个宏可以从ISR中使用,
//但是从ISR中获取信号量不是一种常见的操作。只有当中断从资源池中获取对象时(当信号量计数指示可用资源的数量时),它才可能有用
#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) )
//创建一个新的互斥量类型信号量实例,并返回一个句柄,通过这个句柄可以引用新的互斥量。
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
#endif
//创建一个新的互斥量类型信号量实例,并返回一个句柄,通过这个句柄可以引用新的互斥量。
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
#define xSemaphoreCreateMutexStatic( pxMutexBuffer ) xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) )
#endif /* configSUPPORT_STATIC_ALLOCATION */
//创建一个新的递归互斥量类型信号量实例,并返回一个句柄,通过这个句柄可以引用新的递归互斥量。
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) )
#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )
#endif
//创建一个新的递归互斥量类型信号量实例,并返回一个句柄,通过这个句柄可以引用新的递归互斥量。
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) )
#define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore )
#endif /* configSUPPORT_STATIC_ALLOCATION */
//创建一个新的计数信号量实例,并返回一个句柄,通过该句柄可以引用新的计数信号量。
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
#endif
//创建一个新的计数信号量实例,并返回一个句柄,通过该句柄可以引用新的计数信号量。
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
#define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) )
#endif /* configSUPPORT_STATIC_ALLOCATION */
//删除一个信号量。这个函数必须小心使用。例如,如果互斥对象由任务持有,则不要删除互斥类型信号量。
#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )
//如果xMutex确实是互斥类型信号量,返回当前的互斥锁持有者。如果xMutex不是互斥类型信号量,或者互斥是可用的(不是由任务持有),则返回NULL。
#define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) )
//如果xMutex确实是互斥类型信号量,返回当前的互斥锁持有者。如果xMutex不是互斥类型信号量,或者互斥是可用的(不是由任务持有),则返回NULL。
#define xSemaphoreGetMutexHolderFromISR( xSemaphore ) xQueueGetMutexHolderFromISR( ( xSemaphore ) )
//如果信号量是计数信号量,那么uxSemaphoreGetCount()返回当前的计数值。如果信号量是二进制信号量,那么如果信号量可用,uxSemaphoreGetCount()返回1,如果信号量不可用,返回0。
#define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
5、核心数据结构
#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( uint8_t ) 1U )
#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U )
#define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U )
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
typedef QueueHandle_t SemaphoreHandle_t;
typedef StaticQueue_t StaticSemaphore_t;
6、信号核心函数
/------------------------Create-----------------------------------
// 创建 二值信号量
void vSemaphoreCreateBinary(SemaphoreHandle_t xSemaphore )
xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxStaticSemaphore )
xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE )
//创建 互斥型信号量
SemaphoreHandle_t xSemaphoreCreateMutex(void)
xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )
xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) )
//创建 递归互斥型信号量
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )
xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )
SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )
xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore )
//创建 数值信号量
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )
xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer )
xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) )
/------------------------Take-----------------------------------
//获取 信号量
void xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xBlockTime )
xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
// 获取 递归互斥型信号量
void xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex, TickType_t xBlockTime )
xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )
//中断版本
void xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,BaseType_t *pxHigherPriorityTaskWoken )
xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) )
/------------------------Give-----------------------------------
//发送 信号量
void xSemaphoreGive( SemaphoreHandle_t xSemaphore )
xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
// 发送 递归互斥型信号量
void xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex )
xQueueGiveMutexRecursive( ( xMutex ) )
//中断版本
void xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken )
xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) )
/------------------------Get-----------------------------------
// 获取当前信号量的值
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore )
uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
/------------------------Delete-----------------------------------
// 删除信号量
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )
/------------------------Holder-----------------------------------
// 获取互斥信号量的持有者
TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex )
xQueueGetMutexHolder( ( xSemaphore ) )