当前位置: 首页 > news >正文

freertos 任务调度—抢占式, 时间片

FreeRTOS 操作系统支持三种调度方式: 抢占式调度,时间片调度和合作式调度。 实际应用主要是抢占式调度和时间片调度,合作式调度用到的很少.

1,抢占式调度
每个任务都有不同的优先级, 任务会一直运行直到被高优先级任务抢占或者遇到阻塞式的 API 函数,比如 vTaskDelay(延迟,事件标志等待,信号量等待)才会切换到其他任务。抢占式调度要掌握的最关键一点是: 每个任务都被分配了不同的优先级, 抢占式调度器会获得就绪列表中优先级最高的任务,并运行这个任务

FreeRTOS 操作系统是设置的数值越小任务优先级越低, 数值越大任务优先级越高,由于任务2的优先级高于任务1,因此任务2将首先运行。

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

#define TASK1_PRIORITY   (tskIDLE_PRIORITY + 1)
#define TASK2_PRIORITY   (tskIDLE_PRIORITY + 2)

// 任务函数原型
void vTask1(void *pvParameters);
void vTask2(void *pvParameters);

// 任务1函数
void vTask1(void *pvParameters) {
    const char *pcTaskName = (const char *)pvParameters;

    for (;;) {
        // 打印任务名
        printf("%s is running\n", pcTaskName);

        // 延时一段时间,模拟任务的工作负载
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

// 任务2函数
void vTask2(void *pvParameters) {
    const char *pcTaskName = (const char *)pvParameters;

    for (;;) {
        // 打印任务名
        printf("%s is running\n", pcTaskName);

        // 延时一段时间,模拟任务的工作负载
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

int main(void) {
    // 创建任务
    xTaskCreate(vTask1, "Task 1", configMINIMAL_STACK_SIZE, "Task 1", TASK1_PRIORITY, NULL);
    xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, "Task 2", TASK2_PRIORITY, NULL);

    // 启动调度器
    vTaskStartScheduler();

    // 如果调度器启动失败,将不会到达这里
    for (;;);
}

Task 2 is running
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running

 抢占式调度算法实现。

#include <stdio.h>
#include <stdbool.h>

#define NUM_TASKS 3

typedef struct {
    int priority;
    bool isRunning;
} Task;

void initTask(Task *task, int priority) {
    task->priority = priority;
    task->isRunning = false;
}

void runTask(Task *task) {
    if (task->isRunning) {
        printf("Task with priority %d is running.\n", task->priority);
    }
}

void scheduleTasks(Task *tasks, int numTasks) {
    int highestPriority = -1;
    int highestPriorityTaskIndex = -1;

    // Find the highest priority task that is ready to run
    for (int i = 0; i < numTasks; ++i) {
        if (tasks[i].priority > highestPriority && !tasks[i].isRunning) {
            highestPriority = tasks[i].priority;
            highestPriorityTaskIndex = i;
        }
    }

    // Preempt lower priority tasks
    for (int i = 0; i < numTasks; ++i) {
        tasks[i].isRunning = false;
    }

    // Run the highest priority task
    if (highestPriorityTaskIndex != -1) {
        tasks[highestPriorityTaskIndex].isRunning = true;
        runTask(&tasks[highestPriorityTaskIndex]);
    }
}

int main() {
    Task tasks[NUM_TASKS];

    initTask(&tasks[0], 1);
    initTask(&tasks[1], 2);
    initTask(&tasks[2], 3);

    // Initially, the highest priority task is running
    tasks[2].isRunning = true;

    // Simulate scheduling
    printf("Initial scheduling:\n");
    scheduleTasks(tasks, NUM_TASKS);

    // Now, a higher priority task becomes ready
    printf("\nAfter a higher priority task becomes ready:\n");
    tasks[1].priority = 4; // Increase the priority of task 1
    scheduleTasks(tasks, NUM_TASKS);

    return 0;
}

 2, 时间片调度
每个任务都有相同的优先级, 任务会运行固定的时间片个数或者遇到阻塞式的 API 函数,比如
vTaskDelay, 才会执行同优先级任务之间的任务切换。

在 FreeRTOS 操作系统中只有同优先级任务才会使用时间片调度, 另外还需要用户在
FreeRTOSConfig.h 文件中使能宏定义:#define configUSE_TIME_SLICING 1

每个任务分配的时间片大小是 5 个系统时钟节拍。而在时间片轮询的过程中如果调用了阻塞式 API 函数, 调用函数时, 虽然 5 个系统时钟节拍的时间片大小还没有用完, 此时依然会通过时间片调度切换到下一个任务。

FreeRTOSConfig中:
configUSE_PREEMPTION=0关闭抢占,只有阻塞/挂起/运行的任务调用 taskYIELD()/ISR才会切换下文的任务

configUSE_TIME_SLICING=0关闭时间片,相同优先级的任务不会在tick间隔后切换。

#include "FreeRTOS.h"
#include "task.h"
#include<stdio.h>
#include "timers.h"

void vApplicationMallocFailedHook() {
	while(1);
}
 
void vApplicationStackOverflowHook(TaskHandle_t xTask, char * pcTaskName ) {
	while(1);
}

#define TASK_PRIORITY 1
#define TASK_STACK_SIZE 256
#define TIME_SLICE_MS 1000

// 任务句柄
TaskHandle_t taskHandles[2] = {NULL, NULL};

// 时间片定时器回调函数
void vTimerCallback(TimerHandle_t xTimer) {
    // 交换两个任务的优先级,以实现时间片调度
    vTaskPrioritySet(taskHandles[0], TASK_PRIORITY + 1);
    vTaskPrioritySet(taskHandles[1], TASK_PRIORITY);
}

// 任务函数
void vTaskFunction(void *pvParameters) {
    const char *pcTaskName = (const char *)pvParameters;
    UBaseType_t uxPriority;

    // 获取当前任务的优先级
    uxPriority = uxTaskPriorityGet(NULL);

    for (;;) {
        // 执行任务的工作
        printf("%s is running\n", pcTaskName);

        // 延时,模拟任务工作负载
        vTaskDelay(pdMS_TO_TICKS(TIME_SLICE_MS / 2));
    }
}

int main(void) {
    // 创建两个任务
    xTaskCreate(vTaskFunction, "Task 1", TASK_STACK_SIZE, "Task 1", TASK_PRIORITY, &taskHandles[0]);
    xTaskCreate(vTaskFunction, "Task 2", TASK_STACK_SIZE, "Task 2", TASK_PRIORITY, &taskHandles[1]);

    // 创建一个定时器,用于周期性地切换任务优先级
    TimerHandle_t xTimer = xTimerCreate(
        "Timer", pdMS_TO_TICKS(TIME_SLICE_MS), pdTRUE, (void *)0, vTimerCallback);

    // 启动定时器
    xTimerStart(xTimer, 0);

    // 启动调度器
    vTaskStartScheduler();

    // 如果调度器启动失败,将不会到达这里
    for (;;);
}

Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running

时间片c语言实现算法:

#include <stdio.h>
#include <stdbool.h>

#define NUM_TASKS 2
#define TIME_SLICE 5

typedef struct {
    int priority;
    int timeSliceCount;
    bool isRunning;
} Task;

void initTask(Task *task, int priority) {
    task->priority = priority;
    task->timeSliceCount = 0;
    task->isRunning = false;
}

void runTask(Task *task) {
    if (task->isRunning) {
        printf("Task with priority %d is running for time slice %d.\n", task->priority, task->timeSliceCount);
    }
}

void scheduleTasks(Task *tasks, int numTasks) {
    static int currentTaskIndex = 0;

    // Stop the current task
    tasks[currentTaskIndex].isRunning = false;
    tasks[currentTaskIndex].timeSliceCount = 0;

    // Move to the next task
    currentTaskIndex = (currentTaskIndex + 1) % numTasks;

    // Start the next task
    tasks[currentTaskIndex].isRunning = true;
    tasks[currentTaskIndex].timeSliceCount++;

    // Run the next task
    runTask(&tasks[currentTaskIndex]);
}

int main() {
    Task tasks[NUM_TASKS];

    initTask(&tasks[0], 1);
    initTask(&tasks[1], 2);

    // Simulate round-robin scheduling
    printf("Round-robin scheduling:\n");
    for (int i = 0; i < TIME_SLICE * NUM_TASKS; ++i) {
        scheduleTasks(tasks, NUM_TASKS);
    }

    return 0;
}

 

相关文章:

  • src/pyaudio/device_api.c:9:10: fatal error: portaudio.h: 没有那个文件或目录
  • LeetCode 206. 反转链表
  • 龙芯+FreeRTOS+LVGL实战笔记(新)——06添加二级按钮
  • 【运维监控】influxdb 2.0+telegraf 监控tomcat 8.5运行情况(2)
  • 微信小程序npm扩展能力探究
  • Java代理模式
  • VMware中共享文件夹没了怎么办?
  • Windows 系统中安装 PEM 证书
  • Linux环境下安装FFmpeg的教程
  • 【网络安全】DNS重绑定原理详析
  • 说一下解除docker限制内存警告
  • 风控——贷中管理介绍
  • ApplicationVerifier介绍说明
  • 设计模式之组合设计模式
  • 【机器人建模和控制】读书笔记
  • go语言给结构体绑定方法
  • IP网络广播服务平台upload接口存在任意文件上传漏洞
  • 【网络安全】学过编程就是黑客?
  • java:网络编程
  • Excel和Word日常使用记录:
  • 香港特区立法会通过条例草案便利外地公司迁册来港
  • 女外交官郑璇已任中国驻莫桑比克大使
  • AI含量非常高,2025上海教育博览会将于本周五开幕
  • 一海南救护车在西藏无任务拉警笛开道,墨脱警方:已处罚教育
  • 中央结算公司:减免境外央行类机构账户开户费用
  • 人民日报访巴西总统卢拉:“巴中关系正处于历史最好时期”