一、同步的缺陷:全局变量协同两个任务
1.建立两个任务:CalcTask 、LcdPrintTask
xTaskCreate(CalcTask, "task1", 128, NULL, osPriorityNormal, NULL);
xTaskCreate(LcdPrintTask, "task2", 128, &g_Task2Info, osPriorityNormal, NULL);
-
LcdPrintTask
:- 类型:
TaskFunction_t
- 含义: 任务的入口函数,也就是任务的执行代码的起点。在这个例子中,
LcdPrintTask
是一个函数指针,指向任务的实现函数。
- 类型:
-
"task2"
:- 类型:
const char *
- 含义: 任务的名称,用于调试和管理。这里
task2
是任务的名字。
- 类型:
-
128
:- 类型:
uint16_t
- 含义: 为任务分配的堆栈大小(以字节为单位)。这里
128
表示任务的堆栈大小为 128 字节。
- 类型:
-
&g_Task2Info
:- 类型:
void *
- 含义: 传递给任务的参数。在这个例子中,
&g_Task2Info
是一个指向任务参数的指针,任务运行时可以通过这个指针来获取任务相关的数据。
- 类型:
-
osPriorityNormal
:- 类型:
UBaseType_t
- 含义: 任务的优先级。
osPriorityNormal
是任务的优先级,这个值决定了任务在系统中的调度优先级。
- 类型:
-
NULL
:- 类型:
TaskHandle_t *
- 含义: 用于接收任务的句柄。如果不需要获取任务句柄,可以传入
NULL
。任务句柄可以用来控制任务,比如删除任务或获取任务的状态。
- 类型:
解释:
这行代码的作用是创建一个新的任务 LcdPrintTask
,任务的名字为 "task2"
,堆栈大小为 128 字节,任务在启动时会接收到参数 g_Task2Info
,并且该任务的优先级是 osPriorityNormal
。任务句柄被设为 NULL
,表示我们不需要保存这个任务的句柄信息。
一旦任务创建成功,它会被添加到调度器中,并在合适的时机由操作系统调度执行。
//全局变量
static int g_LCDCanUse = 1;
static volatile 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;
g_time = system_get_ns() - g_time;
vTaskDelete(NULL);
}
void LcdPrintTask(void *params)
{
int len;
while (1)
{
LCD_PrintString(0, 0, "Waiting");
vTaskDelay(3000); //让此任务进入阻塞,3毫秒后执行while (g_calc_end == 0);减少cpu的使用
while (g_calc_end == 0);
/* 打印信息 */
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);
}
}
void LcdPrintTask(void *params)
{
int len;
while (1)
{
LCD_PrintString(0, 0, "Waiting");
vTaskDelay(3000); //让此任务进入阻塞,3毫秒后执行while (g_calc_end == 0);减少cpu的使用
while (g_calc_end == 0);
/* 打印信息 */
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);
}
}
注意:static volatile int g_calc_end = 0;使用volatile让编译器不要去优化,否则在执行任务的时候g_calc_end时刻等于0,不执行后面的代码。
二、互斥的缺陷--同时访问一个资源
1.同时有两个任务要使用lcd
进行优化代码如下:但是在微观条件下,也有可能发送任务切换。
(1)可以使用中断的开关解决互斥问题