FreeRTOS-信号量

基本概念

  • 抽象的来讲,信号量是一个非负整数,所有获取它的任务都会将该整数减一(获取它当然是为了使用资源),当该整数值为零时,所有试图获取它的任务都将处于阻塞状态

二值信号量

  • 二值信号量既可以用于临界资源访问也可以用于同步功能

  • 互斥量有优先级继承机制,二值信号量则没有这个机制

  • 二值信号量更偏向应用于同步功能(任务与任务间的同步或任务和中断间同步)

  • 而互斥量更偏向应用于临界资源的访问
    在这里插入图片描述

  • 将二值信号量看作只有一个消息的队列因此这个队列只能为空或满

计数信号量

  • 计数信号量肯定是用于计数的
  • 信号量的计数值则表示还有多少个事件没被处理
  • 计数型信号量允许多个任务对其进行操作,但限制了任务的数量
    在这里插入图片描述

互斥信号量

  • 互斥信号量其实是特殊的二值信号量,由于其特有的优先级继承机制从而使它更适用于简单互锁,也就是保护临界资源
  • 信号量创建后可用信号量个数应该是满的

递归信号量

  • 任务成功获取几次递归互斥量,就要返还几次,在此之前递归互斥量都处于无效状态,只有持有递归信号量的任务才能获取与释放
  • 对于已经获取递归互斥量的任务可以重复获取该递归互斥量,该任务拥有递归信号量的所有权

信号量控制块

  1. 使用信号量需要包含头文件
#include <semphr.h>
  1. 信号量控制块结构体与消息队列结构体是一模一样的,只不过结构体中某些成员变量代表的含义不一样而已
typedef struct QueueDefinition
{
    
    
	int8_t *pcHead;					
	int8_t *pcTail;					
	int8_t *pcWriteTo;				
	union							
	{
    
    
		int8_t *pcReadFrom;			
		UBaseType_t uxRecursiveCallCount;
	} u;

	List_t xTasksWaitingToSend;		
	List_t xTasksWaitingToReceive;	

	volatile UBaseType_t uxMessagesWaiting;/* 
	表示有效信号量个数 
1. 如果信号量是二值信号量、互斥信号量,这个值是 1 则表示有可用信号量,如果是 0 则表示没有可用信号量。

2. 如果是计数信号量,这个值表示可用的信号量个数,在创建计数信号量的时候会被初始化一个可用信号量个数 uxInitialCount,最大不允许超过创建信号量的初始值 uxMaxCount。
*/
	UBaseType_t uxLength;			/*
最大的信号量可用个数,
1. 如果信号量是二值信号量、互斥信号量,uxLength 最大为 1,因为信号量要么是有效的,要么是无效的。
2. 如果是计数信号量,这个值表示最大的信号量个数,在创建计数信号量的时候将由用户指定这个值 uxMaxCount。
 */
	UBaseType_t uxItemSize;			/*果控制块结构体被用于信号量的时候,则无需存储空间,为 0 即可 */

	volatile int8_t cRxLock;		
	volatile int8_t cTxLock;		

	#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
		uint8_t ucStaticallyAllocated;	
	#endif

	#if ( configUSE_QUEUE_SETS == 1 )
		struct QueueDefinition *pxQueueSetContainer;
	#endif

	#if ( configUSE_TRACE_FACILITY == 1 )
		UBaseType_t uxQueueNumber;
		uint8_t ucQueueType;
	#endif

} xQUEUE;

信号量句柄

typedef QueueHandle_t SemaphoreHandle_t;

创建二值信号量 xSemaphoreCreateBinary()

#define semSEMAPHORE_QUEUE_ITEM_LENGTH		( ( uint8_t ) 0U )

#define queueQUEUE_TYPE_BASE				( ( uint8_t ) 0U )
#define queueQUEUE_TYPE_SET					( ( uint8_t ) 0U )
#define queueQUEUE_TYPE_MUTEX 				( ( uint8_t ) 1U )
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE	( ( uint8_t ) 2U )
#define queueQUEUE_TYPE_BINARY_SEMAPHORE	( ( uint8_t ) 3U )
#define queueQUEUE_TYPE_RECURSIVE_MUTEX		( ( uint8_t ) 4U )


	#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )

  • 没有消息存储空间的队列,信号量用什么表示?其实二值信号量的释放和获取都是通过操作队列结控制块构体成员uxMessageWaiting 来实现的,它表示信号量中当前可用的信号量个数
    在这里插入图片描述

创建计数信号量 xSemaphoreCreateCounting()

	#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
/*
uxMaxCount  		计数信号量的最大值,当达到这个值的时候,信号量不能再被释放。
uxInitialCount 	创建计数信号量的初始值。
返回值					如果创建成功则返回一个计数信号量句柄,用于访问创建的计数信号量。如果创建不成功则返回 NULL。
*/

在这里插入图片描述

信号量删除函数 vSemaphoreDelete()

void vSemaphoreDelete( SemaphoreHandle_t xSemaphore )

#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )

信号量释放函数–普通版


BaseType_t xSemaphoreGive(SemaphoreHandle_t  xSemaphore )	

#define xSemaphoreGive( xSemaphore )		xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
/*
如果信号量满,则返回错误代码(err_QUEUE_FULL)
*/

信号量释放函数–中断版

它不能释放互斥量,这是因为互斥量不可以在中断中使用,互斥量的优先级继承机制只能在任务中起作用,而在中断中毫无意义。


#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken )	xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) )

/*
如果被唤醒的任务的优先级大于当前任务的优先级,那么形参 pxHigherPriorityTaskWoken 就会被设置为 pdTRUE,然后在中断退出前执行一次上下文切换,从 FreeRTOS V7.3.0 版本开始 xHigherPriorityTaskWoken 是一个可选的参数,可以设置为 NULL
*/

信号量获取函数–普通版



#define xSemaphoreTake( xSemaphore, xBlockTime )		xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
/*

xSemaphore 		信号量句柄。
xBlockTime 		等待信号量可用的最大超时时间,单位为 tick(即系统节拍周期)。如果宏 INCLUDE_vTaskSuspend 定义为 1 且形参xTicksToWait 设置为 portMAX_DELAY ,则任务将一直阻塞在该信号量上(即没有超时时间)。
返回值				获 取 成 功 则 返 回 pdTRUE , 获取失败 返 回 errQUEUE_EMPTY。
*/

信号量获取函数–中断版

获取信号量,是一个不带阻塞机制获取信号量的函数,获取对象必须由是已经创建的信号量,信号量类型可以是二值信号量和计数信号量,它与 xSemaphoreTake()函数不同,它不能用于获取互斥量,因为互斥量不可以在中断中使用,并且互斥量特有的优先级继承机制只能在任务中起作用,而在中断中毫无意义。

#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken )	xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) )

Guess you like

Origin blog.csdn.net/u010261063/article/details/121385662