任务调度器--双向列表实现的任务调度系统的简单示例

目录

一 双向链表概述

二 双向列表实现的任务调度系统的简单示例


一 双向链表概述

双向列表(Doubly Linked List)是一种常见的数据结构,它是由一系列结点组成的序列,每个结点都有指向前后相邻结点的指针。双向列表的特点在于每个结点不仅知道它的前驱结点,也知道它的后继结点。这意味着可以从任一方向遍历列表,也可以方便地在列表中间插入和删除结点。

双向列表的典型结构如下所示:

c

深色版本

1struct Node {
2    int data; // 结点数据
3    Node* prev; // 指向前驱结点的指针
4    Node* next; // 指向后继结点的指针
5};

双向列表的优点包括:

  1. 双向遍历:双向列表允许从任一方向遍历列表,这在某些情况下非常有用,特别是当你需要反向遍历列表时。

  2. 插入和删除效率高:在双向列表中,插入和删除操作通常只需O(1)的时间复杂度,因为它只需要更新相邻结点的指针即可。

  3. 空间效率:相比于数组,双向列表不需要预先分配固定数量的空间,而是动态增长和收缩,因此更适合存储大小不确定的数据集。

  4. 灵活性:双向列表可以轻松地在任意位置插入和删除结点,而不必像单向列表那样必须从头部或尾部开始。

双向列表的缺点包括:

  1. 空间开销大:每个结点都需要额外的指针来存储前驱和后继结点的引用,相比单向列表增加了存储空间的需求。

  2. 复杂性:双向列表的实现比单向列表更复杂,需要更多的代码来维护前驱和后继指针的一致性。

在FreeRTOS中,列表和列表项被广泛应用于任务管理。例如,就绪列表和延迟列表就是双向列表的具体应用。每个任务作为一个结点,存储在列表中,通过前驱和后继指针链接起来。当任务的状态改变时,例如从就绪变为延时,它会在列表中移动,这涉及到结点指针的更新。

在实际应用中,双向列表可用于实现缓存、队列、堆栈等数据结构,以及用于存储和组织各种类型的数据。双向列表的灵活性使其成为许多算法和数据结构的基础,特别是在需要高效插入和删除操作的场合。

二 双向列表实现的任务调度系统的简单示例

这是一个使用双向列表实现的任务调度系统的简单示例。在这个例子中,我们将创建一个简单的任务调度器,它可以调度三个任务:TaskA、TaskB和TaskC。这三个任务将轮流执行,每次执行1秒钟。

首先,我们需要定义一个任务结构体,它包含任务函数指针、优先级和当前状态:

c

深色版本

1typedef struct Task {
2    void (*func)(void); // 任务函数指针
3    int priority; // 任务优先级
4    bool is_running; // 是否正在运行
5} Task;

接下来,我们定义一个双向列表结构体,用于存储任务:

c

深色版本

1typedef struct TaskNode {
2    Task task; // 任务
3    struct TaskNode* prev; // 前驱结点
4    struct TaskNode* next; // 后继结点
5} TaskNode;

现在,我们可以创建我们的任务:

c

深色版本

1Task tasks[3] = {
2    { .func = &TaskA, .priority = 1 },
3    { .func = &TaskB, .priority = 2 },
4    { .func = &TaskC, .priority = 3 }
5};
6
7TaskNode nodes[3];

接下来,我们将任务添加到双向列表中:

c

深色版本

1nodes[0].task = tasks[0];
2nodes[0].prev = NULL;
3nodes[0].next = &nodes[1];
4
5nodes[1].task = tasks[1];
6nodes[1].prev = &nodes[0];
7nodes[1].next = &nodes[2];
8
9nodes[2].task = tasks[2];
10nodes[2].prev = &nodes[1];
11nodes[2].next = NULL;

现在,我们有了一个双向列表,其中包含三个任务。我们可以编写一个简单的调度器来轮询任务:

c

深色版本

1void scheduler() {
2    static TaskNode* current_task = &nodes[0]; // 当前任务
3
4    if (!current_task->is_running) {
5        current_task->is_running = true;
6        current_task->task.func(); // 执行任务
7        current_task->is_running = false;
8
9        // 移动到下一个任务
10        current_task = current_task->next ? current_task->next : &nodes[0];
11    }
12}

最后,我们在主程序中调用调度器:

c

深色版本

1int main() {
2    while (true) {
3        scheduler();
4    }
5
6    return 0;
7}

在这个例子中,我们创建了一个简单的任务调度器,它使用双向列表来存储任务。每个任务都有一个优先级,任务按优先级顺序执行。当一个任务执行完后,它会标记自己为非运行状态,然后调度器会找到下一个未运行的任务继续执行。如果所有任务都已运行过,则返回到第一个任务重新开始。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值