厦门网站排名优化价格,建立文档,网站建设多少钱一平米,合肥网站建设首选众龙一、谁上锁就由谁解锁#xff1f; 互斥量、互斥锁#xff0c;本来的概念确实是#xff1a;谁上锁就得由谁解锁。 但是FreeRTOS并没有实现这点#xff0c;只是要求程序员按照这样的惯例写代码。 main函数创建了2个任务#xff1a; 任务1#xff1…一、谁上锁就由谁解锁 互斥量、互斥锁本来的概念确实是谁上锁就得由谁解锁。 但是FreeRTOS并没有实现这点只是要求程序员按照这样的惯例写代码。 main函数创建了2个任务 任务1高优先级一开始就获得互斥锁永远不释放。 任务2任务1阻塞时它开始执行它先尝试获得互斥量失败的话就监守自盗(释放互斥量、开锁)然后再上锁
代码如下
int main( void )
{prvSetupHardware();/* 创建互斥量 */xMutex xSemaphoreCreateMutex( );if( xMutex ! NULL ){/* 创建2个任务: 一个上锁, 另一个自己监守自盗(开别人的锁自己用)*/xTaskCreate( vTakeTask, Task1, 1000, NULL, 2, NULL );xTaskCreate( vGiveAndTakeTask, Task2, 1000, NULL, 1, NULL );/* 启动调度器 */vTaskStartScheduler();}else{/* 无法创建互斥量 */}/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}
两个任务的代码和执行流程如下图所示 A任务1的优先级高先运行立刻上锁 B任务1阻塞C任务2开始执行尝试获得互斥量(上锁)超时时间设为0。根据返回值打印出上锁失败
因为A流程那里没有解锁所以会上锁失败而且超时时间设置为0不会等待获取失败就直接返回BaseType_t成功就返回的是pdTURE。 D任务2监守自盗开锁成功 E任务2成功获得互斥量 F任务2阻塞 可见任务1上的锁被任务2解开了。所以FreeRTOS并没有实现谁上锁就得由谁开锁的功能。 二、优先级反转
假设任务A、B都想使用串口A优先级比较低 任务A获得了串口的互斥量 任务B也想使用串口它将会阻塞、等待A释放互斥量高优先级的任务被低优先级的任务延迟这被称为优先级反转(priority inversion) 如果涉及3个任务可以让优先级反转的后果更加恶劣。 互斥量可以通过优先级继承可以很大程度解决优先级反转的问题这也是FreeRTOS中互斥量和二级制信号量的差别。 程序使用二级制信号量来演示优先级反转的恶劣后果。 main函数创建了3个任务LPTask/MPTask/HPTask(低/中/高优先级任务)代码如下
/* 互斥量/二进制信号量句柄 */
SemaphoreHandle_t xLock;
int main( void )
{prvSetupHardware();/* 创建互斥量/二进制信号量 */xLock xSemaphoreCreateBinary( );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;
}
LPTask/MPTask/HPTask三个任务的代码和运行过程如下图所示 AHPTask优先级最高它最先运行。在这里故意打印这样才可以观察到flagHPTaskRun的脉 冲。 BMPTask开始运行。在这里故意打印这样才可以观察到flagMPTaskRun的脉冲。 CLPTask开始运行获得二进制信号量然后故意打印很多字符 DHP Delay时间到HPTask恢复运行它无法获得二进制信号量一直阻塞等待
// #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
查看串口打印情况更加直观 EMP Delay时间到MPTask恢复运行它比LPTask优先级高一直运行。导致LPTask无法运 行自然无法释放二进制信号量于是HPTask无法运行。 总结 LPTask先持有二进制信号量但是MPTask抢占LPTask使得LPTask一直无法运行也就无法释放信号量导致HPTask任务无法运行优先级最高的HPTask竟然一直无法运行 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);}
} 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 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 26; i) {flagLPTaskRun 1;flagMPTaskRun 0;flagHPTaskRun 0;printf(%c, c i);}printf(\r\n);/* 释放互斥量/二进制信号量 */xSemaphoreGive(xLock);vTaskDelay(xTicksToWait);}
}
优先级继承
/* 互斥量/二进制信号量句柄 */
SemaphoreHandle_t xLock;int main( void )
{prvSetupHardware();/* 创建互斥量/二进制信号量 *///xLock xSemaphoreCreateBinary( );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;
}/*-----------------------------------------------------------*//*-----------------------------------------------------------*/
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 26; i) {flagLPTaskRun 1;flagMPTaskRun 0;flagHPTaskRun 0;printf(%c, c i);}printf(\r\n);/* 释放互斥量/二进制信号量 */xSemaphoreGive(xLock);printf(task_low\r\n);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);printf(task_high\r\n);flagLPTaskRun 0;flagMPTaskRun 0;flagHPTaskRun 1;/* 释放互斥量/二进制信号量 */xSemaphoreGive(xLock);printf(task\r\n);}
}唯一的改变就是 运行时序图如下图所示 AHPTask执行xSemaphoreTake(xLock, portMAX_DELAY); 它的优先级被LPTask继承 BLPTask抢占MPTask运行 CLPTask执行xSemaphoreGive(xLock); 它的优先级恢复为原来值 DHPTask得到互斥锁开始运行 互斥锁的优先级继承可以减小优先级反转的影响