偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.
全部博文(1747)
分类: 其他平台
2018-06-11 14:38:11
FreeRTOS的信号量包括二进制信号量、计数信号量、互斥信号量(以后简称互斥量)和递归互斥信号量(以后简称递归互斥量)。我们可以把互斥量和递归互斥量看成特殊的信号量。
信号量API函数实际上都是宏,它使用现有的队列机制。这些宏定义在semphr.h文件中。如果使用信号量或者互斥量,需要包含semphr.h头文件。
二进制信号量、计数信号量和互斥量信号量的创建API函数是独立的,但是获取和释放API函数都是相同的;递归互斥信号量的创建、获取和释放API函数都是独立的。
SemaphoreHandle_t xSemaphoreCreateBinary( void );
这个函数用于创建一个二进制信号量。二进制信号量要么有效要么无效,这也是为什么叫做二进制的原因。
新创建的信号量处于无效状态,这意味着使用API函数xSemaphoreTake()获取信号之前,需要先给出信号。
二进制信号量和互斥量非常相似,但也有细微的区别:互斥量具有优先级继承机制,二进制信号量没有这个机制。这使得二进制信号量更适合用于同步(任务之间或者任务和中断之间),互斥量更适合互锁。
一旦获得二进制信号量后不需要恢复,一个任务或中断不断的产生信号,而另一个任务不断的取走这个信号,通过这样的方式来实现同步。
低优先级任务Task1 拥有互斥量的时候,如果另一个高优先级任务Task2 也企图获取这个信号量,则低优先级任务 Task1 的优先级会被临时提高,提高到和高优先级任务 Task2 相同的优先级(这就是操作系统中的优先级翻转), 这样Task1 就不会被 Task2 抢断,否则高优先级任务 Task2 将永远不能获取这个互斥量,并且那个拥有互斥量的低优先级任务 Task1 也永远不会被调度.。
互斥量和二进制信号量都是SemaphoreHandle_t类型,并且可以用于任何具有这类参数的API函数中。
创建计数信号量,计数信号量通常用于以下两种情况:
NULL表示信号量创建失败,否则返回信号量句柄。
SemaphoreHandle_t xSemaphoreCreateMutex( void )
创建互斥量。可以使用API函数xSemaphoreTake()和xSemaphoreGive()访问互斥量,但是绝不可以用xSemaphoreTakeRecursive()和xSemaphoreGiveRecursive()访问。
二进制信号量和互斥量非常相似,但也有细微的区别:互斥量具有优先级继承机制,二进制信号量没有这个机制。这使得二进制信号量更适合用于同步(任务之间或者任务和中断之间),互斥量更适合互锁。
一旦获得二进制信号量后不需要恢复,一个任务或中断不断的产生信号,而另一个任务不断的取走这个信号,通过这样的方式来实现同步。
低优先级任务拥有互斥量的时候,如果另一个高优先级任务也企图获取这个信号量,则低优先级任务的优先级会被临时提高,提高到和高优先级任务相同的优先级。这意味着互斥量必须要释放,否则高优先级任务将不能获取这个互斥量,并且那个拥有互斥量的低优先级任务也永远不会被剥夺,这就是操作系统中的优先级翻转。
互斥量和二进制信号量都是SemaphoreHandle_t类型,并且可以用于任何具有这类参数的API函数中。
NULL表示信号量创建失败,否则返回信号量句柄。
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )
用于创建递归互斥量。被创建的互斥量可以被API函数xSemaphoreTakeRecursive()和xSemaphoreGiveRecursive()使用,但不可以被API函数xSemaphoreTake()和xSemaphoreGive()使用。
递归类型的互斥量可以被拥有者重复获取。拥有互斥量的任务必须调用API函数xSemaphoreGiveRecursive()将拥有的递归互斥量全部释放后,该信号量才真正被释放。比如,一个任务成功获取同一个互斥量5次,那么这个任务要将这个互斥量释放5次之后,其它任务才能获取到它。
递归互斥量具有优先级继承机制,因此任务获得一次信号后必须在使用完后做一个释放操作。
互斥量类型信号不可以用在中断服务例程中。
NULL表示互斥量创建失败,否则返回互斥量句柄。
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
删除信号量。如果有任务阻塞在这个信号量上,则这个信号量不要删除。
xSemaphore:信号量句柄
xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait)
获取信号量。信号量必须是通过API函数xSemaphoreCreateBinary()、xSemaphoreCreateCounting()和xSemaphoreCreateMutex()预先创建过的。注意,递归互斥量类型信号量不能使用该函数、不用在中断服务程序中使用该函数。
成功获取到信号量返回pdTRUE,否则返回pdFALSE。
API函数xSemaphoreTake()的另一版本,用于中断服务程序。
信号量成功获取返回pdTRUE,否则返回pdFALSE。
xSemaphoreTakeRecursive(SemaphoreHandle_t xMutex, TickType_t xTicksToWait );
获取递归互斥信号量。互斥量必须是通过API函数xSemaphoreCreateRecursiveMutex()创建的类型。
文件FreeRTOSConfig.h中的宏configUSE_RECURSIVE_MUTEXES必须设置成1,此函数才有效。
已经获取递归互斥量的任务可以重复获取该递归互斥量。使用xSemaphoreTakeRecursive() 函数成功获取几次递归互斥量,就要使用xSemaphoreGiveRecursive()函数返还几次,在此之前递归互斥量都处于无效状态。比如,某个任务成功获取5次递归互斥量,那么在它没有返还5次该递归互斥量之前,这个互斥量对别的任务无效。
成功获取递归互斥量返回pdTURE,否则返回pdFALSE。
xSemaphoreGive(SemaphoreHandle_t xSemaphore )
用于释放一个信号量。信号量必须是API函数xSemaphoreCreateBinary()、xSemaphoreCreateCounting()或xSemaphoreCreateMutex() 创建的。必须使用API函数xSemaphoreTake()获取这个信号量。
这个函数绝不可以在中断服务例程中使用,可以使用带中断保护版本的API函数xSemaphoreGiveFromISR()来实现相同功能。
这个函数不能用于使用API函数xSemaphoreCreateRecursiveMutex()所创建的递归互斥量。
信号量释放成功返回pdTRUE,否则返回pdFALSE。
释放信号量。是API函数xSemaphoreGive()的另个版本,用于中断服务程序。信号量必须是通过API函数xSemaphoreCreateBinary()或xSemaphoreCreateCounting()创建的。这里没有互斥量,是因为互斥量不可以用在中断服务程序中。
xSemaphore:信号量句柄
pxHigherPriorityTaskWoken:如果*pxHigherPriorityTaskWoken为pdTRUE,则需要在中断退出前人为的经行一次上下文切换。从FreeRTOS V7.3.0开始,该参数为可选参数,并可以设置为NULL。
成功释放信号量返回pdTURE,否则返回errQUEUE_FULL。
xSemaphoreGiveRecursive(SemaphoreHandle_t xMutex )
释放一个递归互斥量。互斥量必须是使用 API函数xSemaphoreCreateRecursiveMutex()创建的。文件FreeRTOSConfig.h中宏configUSE_RECURSIVE_MUTEXES必须设置成1本函数才有效。
如果递归互斥量释放成功,返回pdTRUE。
见“8 获取递归互斥量”。
TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex );
返回互斥量持有任务的句柄(如果有的话),互斥量由参数xMutex指定。
如果调用此函数的任务持有互斥量,那么可以可靠的返回任务句柄,但是如果是别的任务持有互斥量,则不总可靠。
文件FreeRTOSConfig.h中宏configUSE_MUTEXES必须设置成1本函数才有效。
返回互斥量持有任务的句柄。如果参数xMutex不是互斥类型信号量或者虽然互斥量有效但这个互斥量不被任何任务持有则返回NULL