4 FreeRTOS信号量
-
4.1 信号量简介
信号量主要是用于对共享资源的访问和任务同步。具体的使用例子就不进行展开。 -
4.2 二值信号量
-
4.2.1 二值信号量简介
二值信号量通常用于互斥访问或同步,二值信号量与互斥信号量非常相似,两者的主要区别是:互斥信号量拥有优先级继承机制,二值信号量没有优先级继承(何为优先级继承,后面将讲述)。因此二值信号量适用于同步(任务与任务或任务与中断间的同步),而互斥信号量适用于简单的互斥访问。
与队列一样,二值信号量的API函数允许设置一个阻塞的时间,如果有多个任务同时阻塞在同一个信号量时那么优先级高的任务先获得信号量。通俗的来讲,二值信号量其实就是一个只有一个队列项的队列,这个特殊的队列要么是满的要么是空的。任务与中断无需知道该队列存储的数据,只需知道该队列是否为空即可。 -
4.2.2 创建二值信号量
函数xSemaphoreCreateBinary( )——新版本
SemaphoreHandle_t xSemaphoreCreateBinary( void );
返回值:
NULL:二值信号量创建失败;
其他值:创建成功的二值信号量的句柄。
函数 xSemaphoreCreateStatic( )
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer);
pxSemaphoreBuffer:此参数为指向一个StaticSemaphore_t类型的变量,用于保存信号量结构体;
返回值:
NULL:二值信号量创建失败;
其他值:创建成功的二值信号量的句柄。
-
4.2.3 释放信号量
函数xSemaphoreGive( ) BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore); 参数: xSemaphore:要释放的信号量句柄; 返回值: pdPASS:释放信号量成功; errQUEUE_FULL:释放信号量失败。 函数xSemaphoreGiveFromISR( ) BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t Semaphore, BaseType_t *pxHigherPriorityTaskWoken )
-
4.2.4 获取信号量
函数xSemaphoreTake( ) BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xBlockTime ); 参数: xSemaphore:要获取的信号量句柄; xBlockTime:阻塞的时间。 返回值: pdTRUE:获取信号量成功; pdPASS:超时,获取信号量失败。 函数xSemaphoreTakeFromISR( ) BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken); 参数: xSemaphore:要获取的信号量句柄; pxHigherPriorityTaskWoken:标记退出该函数后是否需要进行任务切换。
以上信号量的释放及获取函数将适用于计数型信号量、互斥信号量等等。
-
4.3 计数型信号量
-
4.3.1 计数型信号量简介
计数型信号量亦称为数值信号量,其长度将大于1,用户无需关心其队列中存储的数据,我们需要关心的是其队列是否为空。计数型信号量的应用场合:
1) 事件计数
在此场合中,每次事件发生的时候就在事件处理函数中释放信号量(增加信号量的计数值),其他任务获取此信号量(其信号量的计数值将减一)来处理相关的事件。在此类场合中,创建的计数型信号量初始计数值将为0。
2) 资源管理
在此类场合中,信号量值就代表当前资源的可用数量,一个任务要想获得资源的使用权,首先必须获取到信号量,信号量获取成功后,信号量值将会减一。也就是说,当信号量值为0时,说明当前没有可用的资源。当一个任务使用完该资源后一定要释放该信号量,于是释放信号量的时候信号量值将会再次加一。因此在创建该信号量的时候,其初始值为该资源的有效数量。 -
4.3.2 计数型信号量的创建
函数 xSemaphoreCreateCounting( ) SemaphoreHandle_t xSemaphoreCreate( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount); uxMaxCount:计数信号量的最大计数值,当信号量值大于此值时释放信号量将会失败; uxInitialCount:计数信号量的初始值。 函数 xSemaphoreCreateCountingStatic( ) SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer); pxSemaphoreBuffer:指向一个StaticSemaphore_t 类型的变量,用来保存信号量结构体。 返回值: NULL:计数信号量创建失败; 其他值:计数信号量创建成功,返回该计数信号量的句柄。
-
4.4 互斥信号量
-
4.4.1 互斥信号量简介
互斥信号量其实是一个拥有优先级继承的二值信号量,适用于那些需要互斥访问的应用中。在互斥访问中互斥信号量就相当于一把钥匙,当任务想要使用共享资源时就必须先获得此钥匙(获取信号量),使用完之后也必须尽快的归还该钥匙(释放信号量),以便他人使用该资源。
优先级继承:当一个互斥信号量正在被一个低优先级的任务使用,而在此时有一个高优先级任务尝试获取该互斥信号量就会被阻塞等待。此时这个高优先级的任务将会把这个低优先级的任务的任务优先级提升到与自己相同的优先级,此过程就成为优先级继承。其优点是尽可能的降低高优先级任务处于阻塞态的时间,并且将已经出现的“优先级反转”的影响降到最低,但是其未能完全消除优先级反转。
【注意】互斥信号量不能应用在中断服务函数中,原因如下:
互斥信号量有优先级继承的机制,所以只能用在任务中,不能用于中断服务函数;
中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。 -
4.4.2 互斥信号量的创建
函数 xSemaphoreCreateMutex( )——动态创建互斥信号量 SemaphoreHandle_t xSemaphoreCreateMutex( void ); 函数xSemaphoreCreateMutexStatic( )——静态创建互斥信号量 SemaphoreHandle_t xSemaphoreCreateMetexStatic( StaticSemaphore_t *pxMutexBuffer); 以上两函数的返回值: NULL:互斥信号量创建失败; 其他值:创建成功的互斥信号量的句柄。
-
4.5 递归互斥信号量
-
4.5.1 递归互斥信号量简介
递归互斥信号量是一种特殊的互斥信号量,这两者最大的区别是:任务若已获取到互斥信号量就不能再次获取此信号量了,但是递归互斥信号量就不同了,已经获取到递归互斥信号量的任务可以再次获取该递归互斥信号量,并且能获取的次数不受限制,同理成功获取多少次后就需要对其进行多少次的释放。例如:某任务成功获取了10此递归信号量,则该任务需要对该递归互斥信号量释放5次。
递归互斥信号量也具有优先级继承的机制,并且不能在中断服务函数中使用。 -
4.5.2 递归互斥信号量的创建
函数 xSemaphoreCreateRecursiveMutex( ) SemaphoreHandle_t xSemaphoreCreateRecuesiveMutex( void ); 函数 xSemaphoreCreateRecursiveMutexStatic( ) SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer ); 返回值: NULL:递归互斥信号量创建失败; 其他值:创建成功的互斥信号量的句柄。
-
4.5.3 递归互斥信号量的释放
#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) ) 函数原型:BaseType_t xSemaphoreGiveMutexRecursive( QueueHandle_t xMutex ); 参数说明: xMutex:要释放的递归互斥信号量的句柄; 返回值: pdPASS:递归互斥信号量成功释放; pdFAIL:递归互斥信号量未成功释放。
-
4.5.4 递归互斥信号量的获取
#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) \ xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) ) BaseType_t xQueueTakeMutexRecursive(QueueHandle_t xMutex, TickType_t xTickToWait); 参数说明: xMutex:要获取的递归互斥信号量的句柄; xTickToWait:阻塞的时间。 返回值: pdPASS:成功获取到递归互斥信号量; pdFAIL:未成功获取到递归互斥信号量。