官方文章在这里:https://www.freertos.org/taskandcr.html
Task 可以理解为 线程 ,线程当然就是优先级(priority)的概念,如果两个线程,有不同的优先级,当然就是优先级高的优先执行(占用CPU资源)。 那问题来了, 是怎么 占用 呢?
如果一个线程A在运行过程中,另一个优先级更高的线程B启动了(进入 Ready 状态),则B会立即执行(进入 Running 状态),A则立马会停止(进入 Ready 状态)
现在做一个测试程序来验证一下,
测试环境:ESP32-WROOM-32E/IDF v4.3
代码如下:2个线程,task2 高(priority=2) task1 低(priority = 1)
void my_delay(int val)
{
for (int k = 0; k < 10; ++k)
{
int i = 0;
for (; i < 100; ++i)
for (int j = 0; j < 10000; ++j)
;
printf("in dealy... %d\n", val);
}
}
void task(void * pvParameters)
{
int flag = *(int*)pvParameters;
while (true)
{
int tick = XTHAL_GET_CCOUNT();
printf("%d:task%d running...\n", tick,flag);
my_delay(flag);
printf("%d:task%d running...DONE.%d\n", tick, flag,XTHAL_GET_CCOUNT());
vTaskDelay(2000 / portTICK_PERIOD_MS);//SLEEP 2秒钟
}
}
void app_main(void)
{
/* Print chip information */
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
printf("This is %s chip with %d CPU core(s), WiFi%s%s, ",
CONFIG_IDF_TARGET,
chip_info.cores,
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
int flag1 = 1;
xTaskCreate(&task, "task1", 1024 * 2,&flag1 , 1, NULL);
int flag2 = 2;
xTaskCreate(&task, "task2", 1024 * 2,&flag2 , 2, NULL);
vTaskDelay(100);
}
预计结果:先打印 2, 完了再打印 1,实际结果如下(交叉打印):
I (0) cpu_start: Starting scheduler on APP CPU.
This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE,
17780636:task1 running...
17786772:task2 running...
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
17786772:task2 running...DONE.182456170
in dealy... 1
17780636:task1 running...DONE.149535080
分析:与预计结果不相符是因为这个模块是 2 核心的,所以可以同时运行
我们再加一个线程 task 3, priority = 3
int flag1 = 1;
xTaskCreate(&task, "task1", 1024 * 2,&flag1 , 1, NULL);
int flag2 = 2;
xTaskCreate(&task, "task2", 1024 * 2,&flag2 , 2, NULL);
int flag3 = 3;
xTaskCreate(&task, "task3", 1024 * 2,&flag3 , 3, NULL);
运行结果如下:
I (0) cpu_start: Starting scheduler on APP CPU.
This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE,
17786580:task2 running...
50932139:task3 running...
in dealy... 2
17781121:task1 running...
in dealy... 3
in dealy... 2
in dealy... 3
in dealy... 2
in dealy... 3
in dealy... 2
in dealy... 3
in dealy... 2
in dealy... 3
in dealy... 2
in dealy... 3
in dealy... 2
in dealy... 3
in dealy... 2
in dealy... 3
in dealy... 2
in dealy... 3
in dealy... 2
17786580:task2 running...DONE.182470416
in dealy... 3
50932139:task3 running...DONE.149376526
in dealy... 1
in dealy... 1
in dealy... 1
in dealy... 1
in dealy... 1
in dealy... 1
in dealy... 1
in dealy... 1
in dealy... 1
in dealy... 1
17781121:task1 running...DONE.312668596
分析:task3,task2 分属不同核心同时运行,task1因为级别(Priority)低 所以一直等待。 当task2,task3 进入BLOCK状态时,task1 开始执行。与结果预期一致!
接下来带的一个问题,如果级别(Priority)都一样,会怎么运行呢?这里就涉及一个配置问题,请参考:https://www.freertos.org/a00110.html#configUSE_TIME_SLICING
简单的说:
配置打开:则相同级别(priority)的线程同时运行,每个线程会被顺序分配时间片。
配置关闭:相同级别(priority)的线程会顺序执行,先运行的线程会一直运行到结束,另一个线程再开始运行。
我们把三个线程都改成相同的priority:
int flag1 = 1;
xTaskCreate(&task, "task1", 1024 * 2,&flag1 , 1, NULL);
int flag2 = 2;
xTaskCreate(&task, "task2", 1024 * 2,&flag2 , 1, NULL);
int flag3 = 3;
xTaskCreate(&task, "task3", 1024 * 2,&flag3 , 1, NULL);
运行结果如下:
I (0) cpu_start: Starting scheduler on APP CPU.
This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE,
17781552:task1 running...
50932563:task2 running...
50938208:task3 running...
in dealy... 3
in dealy... 2
in dealy... 1
in dealy... 3
in dealy... 2
in dealy... 1
in dealy... 3
in dealy... 2
in dealy... 1
in dealy... 3
in dealy... 2
in dealy... 1
in dealy... 3
in dealy... 2
in dealy... 1
in dealy... 3
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 3
in dealy... 1
in dealy... 3
in dealy... 2
in dealy... 1
in dealy... 3
in dealy... 2
in dealy... 1
in dealy... 3
50938208:task3 running...DONE.247676578
in dealy... 1
17781552:task1 running...DONE.248214922
in dealy... 2
50932563:task2 running...DONE.248237042
分析:结果如预期一致。也说明 ESP32的IDF4.3默认是把 TIME_SLICING 打开的
找到 FreeRTOS.h 并把里面的配置改为 0
#ifndef configUSE_TIME_SLICING
#define configUSE_TIME_SLICING 0 //这里原来是 1
#endif
fullclean 之后重新运行。
为了效果更好,我加了第4个线程
int flag1 = 1;
xTaskCreate(&task, "task1", 1024 * 2,&flag1 , 1, NULL);
int flag2 = 2;
xTaskCreate(&task, "task2", 1024 * 2,&flag2 , 1, NULL);
int flag3 = 3;
xTaskCreate(&task, "task3", 1024 * 2,&flag3 , 1, NULL);
int flag4 = 4;
xTaskCreate(&task, "task4", 1024 * 2,&flag4 , 1, NULL);
这次运行的时候发现一个问题,因为我们的主函数(app_main() )其实也是一个线程,会干扰我们的结果。所以我在 task() 中增加了一个 delay ,保证开始执行的时候,主线程已经结束。
void task(void * pvParameters)
{
int flag = *(int*)pvParameters;
vTaskDelay(150);// 增加这行,以避免主函数干扰
while (true)
{
int tick = XTHAL_GET_CCOUNT();
printf("%d:task%d running...\n", tick,flag);
my_delay(flag);
printf("%d:task%d running...DONE.%d\n", tick, flag,XTHAL_GET_CCOUNT());
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
运行结果如下:
I (0) cpu_start: Starting scheduler on APP CPU.
This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE,
289989045:task2 running...
257656240:task3 running...
291588057:task1 running...
260856198:task4 running...
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
in dealy... 2
in dealy... 1
291588057:task1 running...DONE.421771277
in dealy... 4
in dealy... 3
in dealy... 4
in dealy... 3
in dealy... 4
in dealy... 3
in dealy... 4
in dealy... 3
in dealy... 4
in dealy... 3
in dealy... 4
in dealy... 3
in dealy... 4
in dealy... 3
in dealy... 4
in dealy... 3
in dealy... 4
in dealy... 3
in dealy... 4
260856198:task4 running...DONE.550369295
in dealy... 3
257656240:task3 running...DONE.517558482
in dealy... 2
289989045:task2 running...DONE.551025233
分析:先执行task 1,2,结束后再执行task 3,4 。虽然priority一样,但是顺序执行。如预期一致
--END--