0
点赞
收藏
分享

微信扫一扫

从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十五)互斥量 NO.2 互斥量函数接口讲解

mm_tang 2022-08-26 阅读 59


从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十五)互斥量 NO.2 互斥量函数接口讲解

目录

 

​​一、互斥量创建函数 xSemaphoreCreateMutex():​​

​​二、递归互斥量创建函数 xSemaphoreCreateRecursiveMutex():​​

​​三、互斥量删除函数 vSemaphoreDelete():​​

​​四、互斥量获取函数 xSemaphoreTake():​​

​​五、递归互斥量获取函数 xSemaphoreTakeRecursive():​​

​​六、互斥量释放函数 xSemaphoreGive():​​

​​七、递归互斥量释放函数 xSemaphoreGiveRecursive():​​

一、互斥量创建函数 xSemaphoreCreateMutex():

       xSemaphoreCreateMutex()用于创建一个互斥量, 并返回一个互斥量句柄。 该句柄的原型是一个 void 型的指针,在使用之前必须先由用户定义一个互斥量句柄。要想使用该函数必须在 FreeRTOSConfig.h 中把宏 configSUPPORT_DYNAMIC_ALLOCATION 定义为 1,即开启动态内存分配, 其实该宏在 FreeRTOS.h 中默认定义为 1, 即所有 FreeRTOS 的对象在创建的时候都默认使用动态内存分配方案, 同时还需在 FreeRTOSConfig.h 中把configUSE_MUTEXES 宏定义打开, 表示使用互斥量。

从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十五)互斥量 NO.2 互斥量函数接口讲解_互斥量 

SemaphoreHandle_t MuxSem_Handle;
void vATask( void * pvParameters )
{
/* 创建一个互斥量 */
MuxSem_Handle= xSemaphoreCreateMutex();
if (MuxSem_Handle!= NULL ) {
/* 互斥量创建成功 */
}
}

二、递归互斥量创建函数 xSemaphoreCreateRecursiveMutex():

       要想使用该函数必须在FreeRTOSConfig.h中把宏configSUPPORT_DYNAMIC_ALLOCATIONconfigUSE_RECURSIVE_MUTEXES定义为1。宏configSUPPORT_DYNAMIC_ALLOCATION定义为1即表示开启动态内存分配,其实该宏在FreeRTOS.h中默认定义为1,即所有FreeRTOS的对象在创建的时候都默认使用动态内存分配方案。该函数的具体说明见下表,其实xSemaphoreCreateRecursiveMutex()实际调用的函数就是xQueueCreateMutex()函数,具体的创建过程也不再重复赘述,参考前一小节,下面来看看如何使用xSemaphoreCreateRecursiveMutex()函数。

从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十五)互斥量 NO.2 互斥量函数接口讲解_FreeRTOS_02

SemaphoreHandle_t xMutex;
void vATask( void * pvParameters )
{
/* 创建一个递归互斥量 */
xMutex = xSemaphoreCreateRecursiveMutex();
if ( xMutex != NULL ) {
/* 递归互斥量创建成功 */
}
}

三、互斥量删除函数 vSemaphoreDelete():

互斥量的本质是信号量,直接调用vSemaphoreDelete()函数进行删除即可。

四、互斥量获取函数 xSemaphoreTake():

       如果任务获取互斥量成功,那么在使用完毕需要立即释放,否则很容易造成其他任务无法获取互斥量,因为互斥量的优先级继承机制是只能将优先级危害降低,而不能完全消除。同时还需注意的是,互斥量是不允许在中断中操作的,因为优先级继承机制在中断是无意义的,互斥量获取函数的使用实例具体见代码清

static void HighPriority_Task(void* parameter)
{
BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为 pdTRUE */
while (1) {
printf("HighPriority_Task 获取信号量\n");
//获取互斥量 MuxSem,没获取到则一直等待
xReturn = xSemaphoreTake(MuxSem_Handle,/* 互斥量句柄 */
portMAX_DELAY); /* 等待时间 */
if (pdTRUE == xReturn)
printf("HighPriority_Task Runing\n");
LED1_TOGGLE;
//处理临界资源
printf("HighPriority_Task 释放信号量!\r\n");
xSemaphoreGive( MuxSem_Handle );//释放互斥量
vTaskDelay(1000);
}
}

五、递归互斥量获取函数 xSemaphoreTakeRecursive():

       xSemaphoreTakeRecursive()是一个用于获取递归互斥量的宏,与互斥量的获取函数一样, xSemaphoreTakeRecursive()也是一个宏定义,它最终使用现有的队列机制,实际执行的函数是 xQueueTakeMutexRecursive() 。 互斥量之前必须由xSemaphoreCreateRecursiveMutex()这个函数创建。 要注意的是该函数不能用于获取由函数xSemaphoreCreateMutex()创建的互斥量。要想使用该函数必须在头文件 FreeRTOSConfig.h中把宏 configUSE_RECURSIVE_MUTEXES 定义为 1。 

从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十五)互斥量 NO.2 互斥量函数接口讲解_FreeRTOS_03

       递归互斥量可以在一个任务中多次获取,当第一次获取递归互斥量时,队列结构体成员指针 pxMutexHolder 指向获取递归互斥量的任务控制块,当任务再次尝试获取这个递归互斥量时,如果任务就是拥有递归互斥量所有权的任务,那么只需要将记录获取递归次数的成员变 量 u.uxRecursiveCallCount 加 1即可 ,不需要再操作队列。
 

SemaphoreHandle_t xMutex = NULL;
/* 创建信号量的任务 */
void vATask( void * pvParameters )
{
/* 创建一个递归互斥量,保护共享资源 */
xMutex = xSemaphoreCreateRecursiveMutex();
}
/* 使用互斥量 */
void vAnotherTask( void * pvParameters )
{
/* ... 做其他的事情 */
if ( xMutex != NULL ) {
/* 尝试获取递归信号量。
如果信号量不可用则等待 10 个 ticks */
if(xSemaphoreTakeRecursive(xMutex,( TickType_t)10)==pdTRUE ) {
/* 获取到递归信号量,可以访问共享资源 */
/* ... 其他功能代码 */
/* 重复获取递归信号量 */
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
/* 释放递归信号量,获取了多少次就要释放多少次 */
xSemaphoreGiveRecursive( xMutex );
xSemaphoreGiveRecursive( xMutex );
xSemaphoreGiveRecursive( xMutex );
/* 现在递归互斥量可以被其他任务获取 */
} else {
/* 没能成功获取互斥量,所以不能安全的访问共享资源 */
}
}
}

六、互斥量释放函数 xSemaphoreGive():

① 任务想要访问某个资源的时候,需要先获取互斥量,然后进行资源访问,在任务使用完该资源的时候,必须要及时归还互斥量,这样别的任务才能对资源进行访问。

② 互斥量的释放函数与信号量的释放函数一致,都是调用xSemaphoreGive()函数,但是要注意的是,互斥量的释放只能在任务中,不允许在中断中释放互斥量。

③ 只有已持有互斥量所有权的任务才能释放它,当任务调用xSemaphoreGive()函数时会将互斥量变为开锁状态,等待获取该互斥量的任务将被唤醒。如果任务的优先级被互斥量的优先级翻转机制临时提升,那么当互斥量被释放后,任务的优先级将恢复为原本设定的优先级。

④ 系统会将结构体的pxMutexHolder成员变量指向NULL,表示暂时没有任务持有改互斥量,对结构体成员uxMessagesWaiting加1操作就代表了释放互斥量,表示此时互斥量是有效的,其他任务可以来获取。

SemaphoreHandle_t xSemaphore = NULL;
void vATask( void * pvParameters )
{
/* 创建一个互斥量用于保护共享资源 */
xSemaphore = xSemaphoreCreateMutex();
if ( xSemaphore != NULL ) {
if ( xSemaphoreGive( xSemaphore ) != pdTRUE ) {
/*
如果要释放一个互斥量,必须先有第一次的获取*/
}
/* 获取互斥量,不等待 */
if ( xSemaphoreTake( xSemaphore, ( TickType_t ) 0 ) ) {
/* 获取到互斥量,可以访问共享资源 */
/* ... 访问共享资源代码 */
/* 共享资源访问完毕,释放互斥量 */
if ( xSemaphoreGive( xSemaphore ) != pdTRUE ) {
/* 互斥量释放失败,这可不是我们希望的 */
}
}
}
}

七、递归互斥量释放函数 xSemaphoreGiveRecursive():

       只有已持有互斥量所有权的任务才能释放它,每释放一次该递归互斥量,它的计数值就减1。当该互斥量的计数值为0时,互斥量则变为开锁状态,等待在该互斥量上的任务将被唤醒。如果任务的优先级被互斥量的优先级翻转机制临时提升,那么当互斥量被释放后,任务的优先级将恢复为原本设定的优先级。

        xSemaphoreGiveRecursive()是一个用于释放递归互斥量的宏。要想使用该函数必须在头文件 FreeRTOSConfig.h 把宏 configUSE_RECURSIVE_MUTEXES 定义为 1。

SemaphoreHandle_t xMutex = NULL;
void vATask( void * pvParameters )
{
/* 创建一个递归互斥量用于保护共享资源 */
xMutex = xSemaphoreCreateRecursiveMutex();
}
void vAnotherTask( void * pvParameters )
{
/* 其他功能代码 */
if ( xMutex != NULL ) {
/* 尝试获取递归互斥量
如果不可用则等待 10 个 ticks */
if(xSemaphoreTakeRecursive(xMutex,( TickType_t ) 10 )== pdTRUE) {
/* 获取到递归信号量,可以访问共享资源 */
/* ... 其他功能代码 */
/* 重复获取递归互斥量 */
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
/* 释放递归互斥量,获取了多少次就要释放多少次 */
xSemaphoreGiveRecursive( xMutex );
xSemaphoreGiveRecursive( xMutex );
xSemaphoreGiveRecursive( xMutex );
/* 现在递归互斥量可以被其他任务获取 */
} else {
/* 没能成功获取互斥量,所以不能安全的访问共享资源 */
}
}
}

 

举报

相关推荐

0 条评论