所以二进制并不能保证是谁上锁谁解锁,引入互斥量本质并没有解决这个问题,还是要程序员去解决。引入互斥量可以去解决优先级翻转的问题。
一.优先级反转和优先级继承
二. 递归上锁
获得了锁之后,再次执行任务获得锁。
三.创建互斥量
与前面的信号量差不多,只不过前面创建信号量之前需要give一下,这里创建互斥量不需要give
void TaskGenericFunction(void * param)
{while (1){xSemaphoreTake(xSemUART,portMAX_DELAY);//获得信号量printf("%s\r\n", (char *)param);xSemaphoreGive(xSemUART);//释放信号量vTaskDelay(1);}
}/*-----------------------------------------------------------*/int main( void )
{TaskHandle_t xHandleTask1;#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");xSemCalc=xSemaphoreCreateCounting(10,0);xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);xSemUART=xSemaphoreCreateMutex();xTaskCreate(TaskGenericFunction, "Task3", 100, "Task 3 is running", 1, NULL);xTaskCreate(TaskGenericFunction, "Task4", 100, "Task 4 is running", 1, NULL);/* Start the scheduler. */vTaskStartScheduler();/* Will only get here if there was not enough heap space to create theidle task. */return 0;
}
四.优先级反转和解决优先级反转 (优先级继承)
static volatile uint8_t flagLPTaskRun = 0;
static volatile uint8_t flagMPTaskRun = 0;
static volatile uint8_t flagHPTaskRun = 0;static void vLPTask( void *pvParameters );
static void vMPTask( void *pvParameters );
static void vHPTask( void *pvParameters );/*-----------------------------------------------------------*//* 互斥量/二进制信号量句柄 */
SemaphoreHandle_t xLock;int main( void )
{prvSetupHardware();/* 创建互斥量/二进制信号量 */xLock = xSemaphoreCreateBinary( );xSemaphoreGive(xLock);//给一个初值if( xLock != NULL ){/* 创建3个任务: LP,MP,HP(低/中/高优先级任务)*/xTaskCreate( vLPTask, "LPTask", 1000, NULL, 1, NULL );xTaskCreate( vMPTask, "MPTask", 1000, NULL, 2, NULL );xTaskCreate( vHPTask, "HPTask", 1000, NULL, 3, NULL );/* 启动调度器 */vTaskStartScheduler();}else{/* 无法创建互斥量/二进制信号量 */}/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}/*-----------------------------------------------------------*//*-----------------------------------------------------------*/
static void vLPTask( void *pvParameters )
{const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL ); uint32_t i;char c = 'A';printf("LPTask start\r\n");/* 无限循环 */for( ;; ){ flagLPTaskRun = 1;flagMPTaskRun = 0;flagHPTaskRun = 0;/* 获得互斥量/二进制信号量 */xSemaphoreTake(xLock, portMAX_DELAY);/* 耗时很久 */printf("LPTask take the Lock for long time");for (i = 0; i < 500; i++) {flagLPTaskRun = 1;flagMPTaskRun = 0;flagHPTaskRun = 0;printf("%c", c + i);}printf("\r\n");/* 释放互斥量/二进制信号量 */xSemaphoreGive(xLock);vTaskDelay(xTicksToWait);}
}static void vMPTask( void *pvParameters )
{const TickType_t xTicksToWait = pdMS_TO_TICKS( 30UL ); flagLPTaskRun = 0;flagMPTaskRun = 1;flagHPTaskRun = 0;printf("MPTask start\r\n");/* 让LPTask、HPTask先运行 */ vTaskDelay(xTicksToWait);/* 无限循环 */for( ;; ){ flagLPTaskRun = 0;flagMPTaskRun = 1;flagHPTaskRun = 0;}
}static void vHPTask( void *pvParameters )
{const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL ); flagLPTaskRun = 0;flagMPTaskRun = 0;flagHPTaskRun = 1;printf("HPTask start\r\n");/* 让LPTask先运行 */ vTaskDelay(xTicksToWait);/* 无限循环 */for( ;; ){ flagLPTaskRun = 0;flagMPTaskRun = 0;flagHPTaskRun = 1;printf("HPTask wait for Lock\r\n");/* 获得互斥量/二进制信号量 */xSemaphoreTake(xLock, portMAX_DELAY);flagLPTaskRun = 0;flagMPTaskRun = 0;flagHPTaskRun = 1;/* 释放互斥量/二进制信号量 */xSemaphoreGive(xLock);}
}
高优先级先执行执行Delay(10ms),接着中等优先级执行Delay(30ms),低优先级执行运行获得了LOCK,打印500个字符,高优先级任务想获得锁,没有成功进入阻塞状态,低优先级任务执行30ms到了,中优先级任务就一直执行,没有放弃执行。
修改原来的代码1为下面的代码2
/* 创建互斥量/二进制信号量 */ xLock = xSemaphoreCreateBinary( );xSemaphoreGive(xLock);//给一个初值
/* 创建互斥量/二进制信号量 */xLock = xSemaphoreCreateMutex();
int main( void )
{prvSetupHardware();/* 创建互斥量/二进制信号量 */xLock = xSemaphoreCreateMutex();if( xLock != NULL ){/* 创建3个任务: LP,MP,HP(低/中/高优先级任务)*/xTaskCreate( vLPTask, "LPTask", 1000, NULL, 1, NULL );xTaskCreate( vMPTask, "MPTask", 1000, NULL, 2, NULL );xTaskCreate( vHPTask, "HPTask", 1000, NULL, 3, NULL );/* 启动调度器 */vTaskStartScheduler();}else{/* 无法创建互斥量/二进制信号量 */}/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}
前面一部分跟上面是一样的高优先级先执行,中接着执行,低优先任务最后执行,低优先级任务里面获得了LOCK,10ms执行时间到了高优先级任务想要LOCK,进入阻塞状态同时会优先级继承,最低优先级继承最高优先级,即使到了中优先级该执行的时间了,但是还是低优先级执行,最后UNLOCK,轮到最高优先级执行。
五.互斥量的缺陷和递归锁
递归锁可以实现由谁持有就由谁释放。
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){ if(xSemaphoreTakeRecursive(xSemUART, 0)!=pdTRUE){xSemaphoreGiveRecursive(xSemUART);}else{break;}}printf("%s\r\n", (char *)param); vTaskDelay(1);}
}/*-----------------------------------------------------------*/int main( void )
{TaskHandle_t xHandleTask1;#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");xSemCalc = xSemaphoreCreateCounting(10, 0);//xSemUART = xSemaphoreCreateBinary();//xSemaphoreGive(xSemUART);xSemUART = xSemaphoreCreateRecursiveMutex();xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);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);/* Start the scheduler. */vTaskStartScheduler();/* Will only get here if there was not enough heap space to create theidle task. */return 0;
}
递归上锁解锁
void TaskGenericFunction(void * param)
{int i;while (1){xSemaphoreTakeRecursive(xSemUART, portMAX_DELAY);printf("%s\r\n", (char *)param);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);}
}void Task5Function(void * param)
{vTaskDelay(10);while (1){while(1){ if(xSemaphoreTakeRecursive(xSemUART, 0)!=pdTRUE){xSemaphoreGiveRecursive(xSemUART);}else{break;}}printf("%s\r\n", (char *)param); vTaskDelay(1);}
}/*-----------------------------------------------------------*/int main( void )
{TaskHandle_t xHandleTask1;#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");xSemCalc = xSemaphoreCreateCounting(10, 0);//xSemUART = xSemaphoreCreateBinary();//xSemaphoreGive(xSemUART);xSemUART = xSemaphoreCreateRecursiveMutex();xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);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);/* Start the scheduler. */vTaskStartScheduler();/* Will only get here if there was not enough heap space to create theidle task. */return 0;
}