前情提要
FreeRTOS ~(四)同步互斥与通信 ~ (2/3)互斥的缺陷
FreeRTOS ~(五)队列的常规使用 ~ (2/5)队列解决互斥缺陷
FreeRTOS ~(六)信号量 ~ (2/3)信号量解决互斥缺陷
FreeRTOS ~(七)互斥量 ~ (1/3)互斥量解决互斥缺陷
FreeRTOS ~(七)互斥量 ~ (2/3)互斥量解决优先级反转问题
互斥量的缺陷
static SemaphoreHandle_t xSemUART; /* 互斥量的句柄 */
void TaskGenericFunction(void * param)
{
while (1)
{
/* 将互斥量置0,关闭串口使用权,
防止被Tick中断的时候,任务切换后,其他任务使用串口 */
xSemaphoreTake(xSemUART, portMAX_DELAY);
printf("%s\r\n", (char *)param);
/* 将互斥量置1,激活串口使用权 */
xSemaphoreGive(xSemUART);
vTaskDelay(1);
}
}
void Task5Function(void * param)
{
/* 一进来,先Delay10ms,让其他任务先执行 */
vTaskDelay(10);
while (1)
{
while(1)
{
/* Task5在这里做一个破坏,
无论Task5有没有获得信号量,也就是有没有获得锁,就将该信号量释放掉,
一般来说只有当谁拥有锁的时候,就有谁去释放,这才是正确的 */
if(xSemaphoreTake(xSemUART,0) != pdTRUE)
xSemaphoreGive(xSemUART);
else
break;
}
printf("%s\r\n", (char *)param);
xSemaphoreGive(xSemUART);
vTaskDelay(1);
}
}
/*-----------------------------------------------------------*/
int main( void )
{
prvSetupHardware();
xSemUART = xSemaphoreCreateMutex();
xTaskCreate(TaskGenericFunction, "Task3", 100, "Task 3 is running", 1, NULL);
xTaskCreate(TaskGenericFunction, "Task4", 100, "Task 4 is running", 1, NULL);
xTaskCreate(Task5Function, "Task5", 100, "Task 5 is running", 1, NULL);
vTaskStartScheduler();
return 0;
}
解决互斥量的缺陷---引入递归锁
相较于上述的代码:
更换几个API函数即可;
xSemaphoreTake -> xSemaphoreTakeRecursive
xSemaphoreGive -> xSemaphoreGiveRecursive
xSemaphoreCreateMutex -> xSemaphoreCreateRecursiveMutex
代码如下:
static SemaphoreHandle_t xSemUART;
void TaskGenericFunction(void * param)
{
while (1)
{
xSemaphoreTakeRecursive(xSemUART, portMAX_DELAY);
printf("%s\r\n", (char *)param);
xSemaphoreGiveRecursive(xSemUART);
vTaskDelay(1);
}
}
void Task5Function(void * param)
{
vTaskDelay(10);
while (1)
{
while(1)
{
/* Task5如果没有获得信号量,也就是Task5获得锁不成功,
那么释放这个锁也是不成功的 */
if(xSemaphoreTakeRecursive(xSemUART,0) != pdTRUE)
xSemaphoreGiveRecursive(xSemUART);
else
break;
}
printf("%s\r\n", (char *)param);
xSemaphoreGiveRecursive(xSemUART);
vTaskDelay(1);
}
}
/*-----------------------------------------------------------*/
int main( void )
{
prvSetupHardware();
xSemUART = xSemaphoreCreateRecursiveMutex();
xTaskCreate(TaskGenericFunction, "Task3", 100, "Task 3 is running", 1, NULL);
xTaskCreate(TaskGenericFunction, "Task4", 100, "Task 4 is running", 1, NULL);
xTaskCreate(Task5Function, "Task5", 100, "Task 5 is running", 1, NULL);
vTaskStartScheduler();
return 0;
}
/*-----------------------------------------------------------*/
递归锁解决的就是由谁上的锁,就必须由谁解锁.
这样就解决掉了互斥量自己上锁可能会被别人解锁的缺陷.
递归锁会记录谁是锁的拥有者,且在拥有锁的时候可以不断的执行加锁开锁这样的过程.
如下方式修改代码,就可以看到这样的过程.
void TaskGenericFunction(void * param)
{
int i;
while (1)
{
xSemaphoreTakeRecursive(xSemUART, portMAX_DELAY);
printf("%s\r\n", (char *)param);
/* 上面已经Take了,说明获得锁了,
那么就可以不断的上锁解锁 */
for(i = 0; i < 10; i++)
{
xSemaphoreTakeRecursive(xSemUART, portMAX_DELAY);
printf("%s in loop %d\r\n", (char *)param,i);
xSemaphoreGiveRecursive(xSemUART);
}
/* 最后使用完就解锁 */
xSemaphoreGiveRecursive(xSemUART);
vTaskDelay(1);
}
}