目录
实时操作系统基本上都是通过一些链表进行线程、信号、队列的管理,RT_Thread也不例外,本章主要讲解RT_Thread的链表结构和对象管理。
本章基于RT_Thread Nano V3.1.5版本分析
1、链表
RT_Thread使用的链表非常简单,链表节点只有节点指针,各节点在实例结构体中定义,可以通过头节点定位链表,可以通过节点在结构体中的偏移定位实例结构体。
1.1 双向链表
1.1.1 链表结构
双向链表结构声明如下
struct rt_list_node
{
struct rt_list_node *next; /**< 指向下一个节点. */
struct rt_list_node *prev; /**< 指向上一个节点. */
};
双向链表通过一个头节点对整个链表管理,如下所示,NODE1为头节点,用于定位链表,NODE2~NODEn为被链表管理的节点。
双向链表主要用于对象、线程、定时器等实例管理,这些管理均需要提前设置头节点,如下所示,为系统内核定义的双链表头节点,还有一些头节点在结构体中定义,此处不再详述。
/********线程全局变量********/
extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; // 就绪线程链表数组
extern rt_list_t rt_thread_defunct; // 失效线程链表
/* 软件定时器链表 soft timer list */
static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
/* 硬件定时器 hard timer list */
static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
1.1.2 链表操作
链表操作采用内联函数和宏定义的方式,可以免去操作时的环境存储与恢复,提高运行效率。操作接口主要有初始化、插入节点(表头或表尾)、删除节点。
初始化
/*节点初始化(节点指针均指向自己)*/
#define RT_LIST_OBJECT_INIT(object) { &(object), &(object) }
/*链表头节点初始化(节点指针均指向自己)*/
rt_inline void rt_list_init(rt_list_t *l)
{
l->next = l->prev = l;
}
插入节点至表头
/*节点n插入到链表l的头部*/
rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n)
{
l->next->prev = n;
n->next = l->next;
l->next = n;
n->prev = l;
}
NODE1为头节点,用于定位链表,NODE2~NODEn为链表管理的节点,NewNode为新插入的节点。
插入节点至表尾
/*节点n插入到链表l的尾部*/
rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n)
{
l->prev->next = n;
n->prev = l->prev;
l->prev = n;
n->next = l;
}
NODE1为头节点,用于定位链表,NODE2~NODEn为链表管理的节点,NewNode为新插入的节点。
删除节点
/*链表移除节点n*/
rt_inline void rt_list_remove(rt_list_t *n)
{
n->next->prev = n->prev;
n->prev->next = n->next;
n->next = n->prev = n;
}
NODE1为头节点,用于定位链表,DeleteNode、NODE2~NODEn为链表管理的节点,该图为删除节点DeleteNode。
1.1.3 链表遍历
链表遍历接口采用内联函数和宏定义的方式,可以免去操作时的环境存储与恢复,提高运行效率。
链表节点多数存储在各类对象的结构体中,当遍历到一个节点时,可通过节点在结构体中的偏移获取结构体指针。所以链表本质上是对对象(结构体)的管理,因此,链表遍历不仅可以遍历节点,还可以遍历对象(结构体)。
/****判断链表条目数为空****/
rt_inline int rt_list_isempty(const rt_list_t *l)
{
return l->next == l;
}
/****获取链表长度****/
rt_inline unsigned int rt_list_len(const rt_list_t *l)
{
unsigned int len = 0;
const rt_list_t *p = l;
while (p->next != l)
{
p = p->next;
len ++;
}
return len;
}
/****遍历链表节点(pos为遍历出的节点,head为头节点)*/
#define rt_list_for_each(pos, head) \
for(pos=(head)->next;pos!= (head);pos = pos->next)
/*****遍历链表节点(安全模式,防止误删除,pos为遍历出的节点,n指向pos下个节点,head为头节点) */
#define rt_list_for_each_safe(pos, n, head) \
for(pos=(head)->next,n=pos->next; pos!=(head); pos=n, n=pos->next)
/****定位对象(根据节点定位)***/
#define rt_container_of(ptr,type,member) ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/****获取元素*/
#define rt_list_entry(node, type, member) rt_container_of(node, type, member)
/*****遍历对象*/
#define rt_list_for_each_entry(pos, head, member) \
for(pos=rt_list_entry((head)->next,typeof(*pos),member);&pos->member!=(head);pos = rt_list_entry(pos->member.next, typeof(*pos), member)
/******遍历对象(安全模式,防止误删除) */
#define rt_list_for_each_entry_safe(pos, n, head, member) \
for (pos = rt_list_entry((head)->next, typeof(*pos), member), \
n = rt_list_entry(pos->member.next, typeof(*pos), member); \
&