FreeRTOS—互斥信号量
文章目录
一、互斥信号量
1.1.简介
互斥信号量是一个拥有优先级继承的二值信号量,在同步的应用中二值信号量最适合,互斥信号量适用与需要互斥访问的应用中。
1.2.优先级继承
当一个互斥信号量正在被一个低优先级的任务持有时,如果此时有一个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞,不过这个高优先级的任务会将低优先级任务的优先级提升至与自己相同的优先级。
1.3.注意事项
优先级继承不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响;互斥信号量不能用于中断服务函数中,原因如下:
- 互斥信号量有任务优先级继承的机制,但中断不是任务,没有任务优先级,所以互斥信号量只能用于任务中,不能用于中断服务函数
- 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态
1.4.互斥信号量相关的API函数
使用互斥信号量之前,先将宏configUSE_MUTEXES
置一;它的使用流程:创建互斥信号量 - 获取信号量 - 释放信号量。
xSemaphoreCreateMutex( )
xSemaphoreCreateMutexStatic( )
还需注意:创建互斥信号量时,会主动释放一次信号量;互斥信号量的释放和获取函数与二值信号量相同,只不过互斥信号量不支持中断中调用。
#define xSemaphoreCreateMutex()xQueueCreateMutex(queueQUEUE_TYPE_MUTEX)
下面表格是它的返回值:
二、实验
2.1.实验设计
本次实验设计四个任务,步骤与优先级翻转问题的文章一致,将创建二值信号量改为创建互斥信号量即可。
2.2.软件设计
在入口函数里创建互斥信号量并自动生成资源:
void freertos_demo(void){mutex_semphr_handle = xSemaphoreCreateMutex();if(mutex_semphr_handle != NULL){printf(\"二值信号量创建成功\\r\\n\");} xTaskCreate((TaskFunction_t) start_task, (char*) \"start_task\", (uint16_t) START_TASK_STACK_SIZE, (void*) NULL, (UBaseType_t) START_TASK_PRIO, (TaskHandle_t*) &start_task_handler); vTaskStartScheduler(); }
void low_task(void *pvParameters){while(1){xSemaphoreTake(semphr_handle, portMAX_DELAY);printf(\"低优先级任务获取信号量成功\\r\\n\");printf(\"低优先级任务正在运行\\r\\n\");delay_ms(5000);printf(\"低优先级任务释放信号量\\r\\n\");xSemaphoreGive(semphr_handle);vTaskDelay(1000);}}void middle_task(void *pvParameters){uint8_t i = 0;while(1){printf(\"中等任务运行:%d\\r\\n\",++i);vTaskDelay(1000);}}void high_task(void *pvParameters){while(1){xSemaphoreTake(semphr_handle, portMAX_DELAY);printf(\"高优先级任务获取信号量成功\\r\\n\");printf(\"高优先级任务正在运行\\r\\n\");delay_ms(1000);printf(\"高优先级任务释放信号量\\r\\n\");xSemaphoreGive(semphr_handle);vTaskDelay(1000);}}
下图是运行结果:
使用了互斥信号量,使得任务按规定优先级运行,创建互斥信号量之后,高优先级任务就会先一步获得信号量,接着运行至低优先级,低优先级任务获取信号量之后,进行 5s 的时间运行任务,这个时候低优先级任务的优先级与高优先级任务的优先级一样,这时,高优先级的任务和中等优先级的任务一同进入就绪态,但是高优先级的任务它的优先级较高,因此,接下来就会先是运行高优先级的任务再按顺序到低优先级的任务。