返回

链表:双向通用链表

闲谈

各位看官,今天咱们来聊聊链表。在学习 RTOS LiteOS 内核源码时,我们发现 LiteOS 使用的是通用链表,而 FreeRTOS 使用的是非通用链表。所以,今天我们就来探究一下链表实现的奥秘。

首先,我们先从链表的基本概念说起。链表是一种线性数据结构,由一组称为节点的元素组成。每个节点包含数据和指向下一个节点的指针。想象一下一个环形的晾衣架,每个衣服就是链表中的一个节点,而晾衣架的杆子就是链表本身。

通用链表和非通用链表有什么区别呢?通用链表中的每个节点都包含一个指向头节点的指针,而非通用链表中的节点不包含这个指针。也就是说,通用链表可以从任意节点开始遍历整个链表,而非通用链表只能从头节点开始遍历。

那么,在 RTOS 中,为什么 LiteOS 选择使用通用链表,而 FreeRTOS 使用非通用链表呢?这是因为 LiteOS 采用的是微内核架构,需要支持灵活的线程调度和内存管理。通用链表可以方便地从任意节点开始遍历,更适合这种场景。

下面,我们来举个例子,看看如何使用通用链表来管理任务队列。我们定义一个任务节点结构体,其中包含任务数据和指向下一个任务节点的指针:

typedef struct TaskNode {
    Task task;
    struct TaskNode *next;
} TaskNode;

然后,我们可以使用通用链表来管理任务队列:

// 任务队列头节点
TaskNode *head = NULL;

// 入队
void enqueue(TaskNode *node) {
    if (head == NULL) {
        head = node;
        node->next = node;
    } else {
        node->next = head->next;
        head->next = node;
    }
}

// 出队
TaskNode *dequeue() {
    if (head == NULL) {
        return NULL;
    } else if (head->next == head) {
        TaskNode *node = head;
        head = NULL;
        return node;
    } else {
        TaskNode *node = head->next;
        head->next = node->next;
        return node;
    }
}

通过使用通用链表,我们可以从任务队列中的任意节点开始遍历,这大大提高了任务调度的效率。