FreeRTOS (了解同步互斥的缺陷)

📅 发布时间:2026/8/15 8:16:09
FreeRTOS (了解同步互斥的缺陷)
同步Synchronization信号量含义一个任务等待某个事件发生事件来了任务才继续执行任务之间配合完成工作。生活类比等快递。快递员任务 A送完快递事件发生你任务 B收到通知才开门取件。典型场景按键检测任务检测到按键按下通知业务任务处理串口收到数据通知解析任务处理。互斥Mutual Exclusion互斥锁 mutex含义同一个共享资源同一时刻只允许一个任务使用任务之间互相排斥。目的防止多个任务同时访问同一个资源造成错乱。生活类比公共厕所。同一时间只能一个人进去其他人排队等待。典型场景多个任务操作同一个 LCD、串口、全局变量。同步的缺陷同步代码示例staticintg_LCDCanUse1;//判断任务一是否执行完执行完置1执行任务二volatile是告诉CPU这个值是随时变化的要到内存去取值staticvolatileintCalcTask_Flag0;staticuint64_tg_Time;staticuint32_tg_Sum;staticuint32_ti;voidCalcTask(void*parms){g_Timesystem_get_ns();for(i0;i10000000;i){g_Sumi;}g_Timesystem_get_ns()-g_Time;//计算时间CalcTask_Flag1;vTaskDelete(NULL);}voidLcdPrintTask(void*parms){intlen;while(1){LCD_PrintString(0,0,Waiting Time);while(CalcTask_Flag0);if(g_LCDCanUse1){g_LCDCanUse0;LCD_ClearLine(0,0);LCD_ClearLine(0,2);lenLCD_PrintString(0,0,sum:);//赋值字符串长度给lenLCD_PrintHex(len,0,g_Sum,0);//pre0: 不带0x前缀LCD_ClearLine(0,2);lenLCD_PrintString(0,2,Time:);//赋值字符串长度给lenLCD_PrintSignedVal(len,2,g_Time/1000000);//显示时间g_LCDCanUse1;}vTaskDelete(NULL);}}现象在原代码基础上加了这个让任务二在任务一执行的时候进入阻塞状态不参与任务调度现象变成这样可以看到时间减少了一半这说明任务二在等待任务一执行的时候会浪费很多的CPU资源所以我们使用同步的需思考怎么提高处理器的性能让那些等待的任务进入阻塞不参与CPU的调度互斥的缺陷从这个图我们可以看到如果在红框内执行代码假设任务A发出一个start信号然后任务调度器切到了任务B执行这时任务B又发出一个start信号和发送地址这个I2C时序就被打乱了所以使用红框代码来操作LCD时要互斥使用必须等任务A执行完才能轮到你任务B执行这时我们使用了全局变量来保护临界资源但这能万无一失吗往下看可以看到假设任务A执行到了108行的时候切换到了任务B执行这时因为任务A还没将变量设置为0所以任务B还是能进入这个if语句的但任务B执行红框内代码执行到一半时又切换到任务A因为任务A是在108行被切换的所以它也能进入if语句里面将变量再次置0也同样能操控I2C那这时I2C时序又被打乱了虽然这个概率很小但不是不可能。再举一个例子从这个图中我们假设有任务A和任务B来执行这个函数在汇编语言中bCanUse–代码可以拆分为三条汇编指令假设任务A刚刚将bCanUse变量的值写入到R0寄存器时就切换到任务B执行那么因为bCanUse没有被改变所以任务B还是能继续执行当任务B执行if语句执行到一半时因为任务A已经将bCanUse变量的值写入到R0寄存器了所以它也能正常执行任务这时I2C时序又被打断了怎么办呢既然是在设置变量这里因为切换任务出现了问题那我们关中断不就好了吗如下示例一示例二可以看到我们在判断修改这个变量之前就把中断给关掉等我们修改完变量在重新开启中断这样不就行了吗不过这里依旧有不足以示例一为例子可以看到假设当A在执行任务时因为变量的改变任务B无法进入到while循环里面但任务B还是不断执行申请进入到while循环这些没有意义的事情那这不就跟同步一样占用了CPU资源吗所以我们要在任务A还没有执行完时让任务B进入阻塞状态不参与任务的调度当任务A执行完后会把任务B唤醒让任务B去执行任务这样就能提高CPU运行效率任务之间的通信两个任务之间怎么通信上面同步的例子已经告诉我们全局变量任务A把计算结果放到全局变量里然后任务B读取这个全局变量这就实现了通信的目的那如果我任务A写这个变量写到一半的时候任务B就来读取这个变量那任务B读取的就是一个错误的值这是有可能的所以怎么通信不重要重要的是怎么保证通信的结果是正确的所以我们引用了互斥的方法在互斥的情况下通信除了互斥我们还要提高效率FreeRTOS就提供了很多方法首先通过互斥的方法来保证通信的正确性又通过阻塞和唤醒的同步机制来提高效率下面是提供的多种方法