欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > FreeRtos同步互斥与通信

FreeRtos同步互斥与通信

2024/10/24 12:00:37 来源:https://blog.csdn.net/weixin_62292999/article/details/142378892  浏览:    关键词:FreeRtos同步互斥与通信

                        前言:本篇笔记参考韦东山老师,视屏教程,连接放在最后。

同步与互斥的基本概念

        同步:Task_a执行完成之后Task_b才能执行,让任务按照特定的顺序去执行。

        互斥:当Task_a访问临界资源进行执行,Task_b就不能执行,反之也成立。

这两个概念的主要区别就是,同步是有特定顺序的,互斥不是,互斥是谁访问到临界资源谁就执行,没有访问到的就等待,执行结束释放资源,在此访问执行。

Task同步代码体现

static int g_LCDCanUse = 1;
static voltile int g_calc_end = 0;    //实现同步的标志位
static uint64_t g_time = 0;
static uint32_t g_sum = 0;void CalcTask(void *params)
{uint32_t i = 0;LCD_PrintString(0, 0, "Waiting");g_time = system_get_ns();for (i = 0; i < 10000000; i++){g_sum += i;}g_calc_end = 1;//更新标志位 允许task2跑g_time = system_get_ns() - g_time;vTaskDelete(NULL);
}void LcdPrintTask(void *params)
{int len;while (1){LCD_PrintString(0, 0, "Waiting");vTaskDelay(3000);while (g_calc_end == 0);//判断task1,完成没/* 打印信息 */if (g_LCDCanUse){g_LCDCanUse = 0;LCD_ClearLine(0, 0);len = LCD_PrintString(0, 0, "Sum: ");LCD_PrintHex(len, 0, g_sum, 1);LCD_ClearLine(0, 2);len = LCD_PrintString(0, 2, "Time(ms): ");LCD_PrintSignedVal(len, 2, g_time/1000000);g_LCDCanUse = 1;}vTaskDelete(NULL);}
}
xTaskCreate(CalcTask, "task1", 128, NULL, osPriorityNormal, NULL);
xTaskCreate(LcdPrintTask, "task2", 128, &g_Task2Info, osPriorityNormal, NULL);

        这里task1和task2两个任务实现了同步,task2的执行必须在task1后面,但是这里其实还是有一点问题的,task2在等待static int  g_calc_end 标志位的时候,是有cpu分配时间的,如果想让任务执行更快,可以估算Task1的执行时间,将Task2使用vTaskDelay()进行延时

Task互斥代码体现

01 int LCD_PrintString(int x, int y, char *str) 
02 { 
03 static int bCanUse = 1; 
04 if (bCanUse) 
05 { 
06 bCanUse = 0; 
07 /* 使用LCD */ 
08 bCanUse = 1; 
09 return 0; 
10 } 
11 return -1; 
12 } xTaskCreate(LcdPrintTask, "task1", 128, &g_Task1Info, osPriorityNormal, NULL);
xTaskCreate(LcdPrintTask, "task2", 128, &g_Task2Info, osPriorityNormal, NULL);
xTaskCreate(LcdPrintTask, "task3", 128, &g_Task3Info, osPriorityNormal, NULL);

        在文件中,三个task任务使用 LcdPrintTask函数作为执行函数,但是OLED屏幕是一种互斥资源,在这里代码里面使用了标志位   g_LCDCanUse  ,来防止使用Oled的过程被其他Task打断,这里通过堆标志位,进行赋值可以防止大部分情况下的Task进行切换,但是当Task1,执行到if语句,也就是第10行,这个时候切换为Task2,发现Task2也是能够正常执行的,这就会造成IIC通信时序混乱,但是这种概率很小。      

01 int LCD_PrintString(int x, int y, char *str) 
02 { 
03 static int bCanUse = 1; 
04 bCanUse--; 
05 if (bCanUse == 0) 
06 { 
07 /* 使用LCD */ 
08 bCanUse++; 
09 return 0; 
10 } 
11 else 
12 { 
13 bCanUse++; 
14 return -1; 
15 } 
16 }

        第一段代码中实现资源互斥,有小概率出现没有效果,是因为标志位,判断还有赋值占用时间太长了,第二段代码中,将标志位的赋值放在进入判断之前,相对于第一段代码的效果好很多,但是仍然会导致,访问Oled资源的时候无法实现互斥访问。

01 int LCD_PrintString(int x, int y, char *str) 
02 { 
03 static int bCanUse = 1; 
04 disable_irq(); 
05 if (bCanUse) 
06 { 
07 bCanUse = 0; 
08 enable_irq(); 
09 /* 使用LCD */ 
10 bCanUse = 1; 
11 return 0; 
12 } 
13 enable_irq(); 
14 return -1; 
15 }

        上面两段代码,无法完全实现互斥访问oled资源的很大一部分原因,是因为Task之间的切换运行,也就是多Task运行,在进项判断的时候如果可以将中断关闭,不在进行Task切换,就能够完全实现,对Oled资源的互斥访问

        最后这一段代码,可以实现对Oled资源互斥,没有任何漏洞,但是在Task_b使用cpu资源进行判断是否能够执行OLed任务的时候,是一种对cpu资源的浪费,和上面同步的缺陷一样。

        有没有一种办法,在task-a执行的时候,让Task_b进入阻塞状态放弃cpu资源,加快Task_a的执行,同时也可以完成Oled资源访问的互斥。

开发快捷键

        这里记录一个开发快捷键技巧,当在开发的时候,需要看函数原型定义,理解这个函数干什么的时候,可以使用 ctrl+f 快捷键查找函数原型,但是这种方法会找所有相同函数名出现的地方,知道找到函数原型定义在停止,比较慢。

        首先

         然后直接鼠标右键,看里面的选项注释,里Go To Definition of  "ADC_NTC_Temperature",跳转到函数定义,然后后面有快捷键F12,或者直接点击这个选型就可以了,这里点击这个选型进行跳转。

        这个时候发现就已经跳转过来了。很实用的一个小技巧。

                                        感谢阅读,如有错误,欢迎指正!!!

[6-1]_同步互斥与通信_有缺陷的同步示例_哔哩哔哩_bilibili

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com