Freertos,嵌入式

高优先级任务是如何立即抢占低优先级任务的?不要用GPT水,最好有代码讲解

高优先级任务抢占低优先级任务的时间片是要通过os的task调度来实现的,也不是严格的立即,被切换的低优先级任务还是要有个保存现场的过程的。每次调度时,os 调度器就会选择当前最高优先级的任务运行,相当于抢占了低优先级任务的时间。

  • 这篇博客: FreeRTOS知识点总结中的 3.3.3 任务栈水位检测函数 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 函数uxTaskGetStackHighWaterMark (TaskHandle_t xTask),可返回自任务运行以来剩余可用堆栈空间的最小值,即任务运行过程中堆栈最大使用量时还剩余多少空间

    • 打开包含
    #define INCLUDE_uxTaskGetStackHighWaterMark	1
    
    • 如果函数返回0则说明可能发生了任务堆栈溢出

你好,你的这个需求是可以设计实验来观察到,任务代码如下:

#include "test_task.h"
#include "main.h"

osThreadId TaskAHandle;
osThreadId TaskBHandle;

void StartTaskA(void const * argument)
{
    while (1) {
        printf("TaskA is running\r\n");
        vTaskDelay(1000 / portTICK_PERIOD_MS); // 延迟1s
    }
}


void StartTaskB(void const * argument)
{

    while (1) {
        printf("TaskB is running\r\n");
        vTaskDelay(2000 / portTICK_PERIOD_MS); // 延迟2s
    }
}


void InitTestTask(void)
{
    osThreadDef(TaskA, StartTaskA, osPriorityAboveNormal, 0, 128);  // 任务A 稍低的优先级
    TaskAHandle = osThreadCreate(osThread(TaskA), NULL);

    osThreadDef(TaskB, StartTaskB, osPriorityHigh, 0, 128);  // 任务B 稍高的优先级
    TaskBHandle = osThreadCreate(osThread(TaskB), NULL);
}

img

每当任务A打印2条信息后,任务B就会打印1条信息,然后再回到任务A。这说明任务A被任务B打断了。从而验证了高优先级任务可以立即抢占低优先级任务

以下回答参考GPT,并由JoseKe整理完成,希望您能采纳:
在Freertos中,任务的优先级是通过设定数值实现的。数值越高的任务,优先级越高。如果两个任务的优先级相同,那么就按照先后顺序执行。

当高优先级任务就绪后,如果当前正在执行的任务优先级比它低,那么高优先级任务就会抢占低优先级任务。这一过程是由任务调度器自动完成的。

在任务调度时,任务调度器会检查所有就绪任务的优先级,并将优先级最高的任务从就绪链表中取出,准备执行。如果当前正在执行的任务的优先级比该任务的优先级低,那么调度器就会把当前任务从处理器中移除,并将该优先级更高的任务加入处理器中,执行该任务。

下面是示例代码:

c
void vTask1(void *pvParameters)
{
char *pcTaskName = "Task 1 is running
";
volatile uint32_t ul;
for( ;; )
{
/* 模拟任务1在执行 */
for(ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
{
/* 用来进行延时 */
}

/* 任务1是高优先级任务,每次打印前必须先确认是否抢占了任务2 */
if(!eTaskGetState(xTask2))
{
vTaskSuspend(xTask2); /* 挂起任务2 */
printf("Task 1 is running, and has preempted Task 2
");
}

/* 执行任务1的操作 */
printf(pcTaskName);

/* 任务1执行结束,如果任务2被挂起了,必须先唤醒任务2才能结束挂起 */
if(eTaskGetState(xTask2) == eSuspended)
{
vTaskResume(xTask2);
}
}
}

void vTask2(void *pvParameters)
{
char *pcTaskName = "Task 2 is running
";
volatile uint32_t ul;
for( ;; )
{
/* 模拟任务2在执行 */
for(ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
{
/* 用来进行延时 */
}

/* 任务2是低优先级任务 */
printf(pcTaskName);
}
}

int main()
{
xTaskCreate( vTask1, "Task 1", 240, NULL, 3, &xTask1 );
xTaskCreate( vTask2, "Task 2", 240, NULL, 2, &xTask2 );
vTaskStartScheduler();

return 0;
}


在这个示例中,任务1的优先级比任务2高。如果任务1在执行时,发现任务2没有被挂起,那么任务1就会直接执行,不会产生抢占行为。但是,如果任务2正在执行,任务1就会将任务2挂起,抢占它的执行权。直到任务1执行结束并且唤醒了任务2,任务2才会继续执行。

```c
freertos是事件片调度的,整个程序运行的时间被切割成许多很小的时间片,所以你说的立刻并不准确,
只是在下一个事件片中,低优先级任务被高优先级任务抢占,而一个时间片很短,感觉像是立刻。
关于事件片,你可以理解为时基单元,程序是一个时基跟着一个时基运行,
每一个事件片的开始调度器会进行任务调度,选择当前就绪的任务中优先级最高的任务;

想要最简单的了解时间片,可以再freertos配置中开启同优先级任务交替运行的宏,
然后创建两个优先级相同的任务,通过打印或其他形式观察两任务的运行机制
两任务会在在时间片1运行任务1,时间片2运行任务2,时间片3运行任务1,以此往复


```