根据提供的代码片段,_timer_start() 函数的实现确实存在未达预期的关键问题,主要集中在缺少重新插入定时器到计时队列的逻辑。以下是详细分析和解决方案:
问题分析
功能缺失:
- 函数只调用了
_timer_remove(timer) 移除定时器并清除激活标志(RT_TIMER_FLAG_ACTIVATED),但未将定时器重新插入计时队列。
- 导致定时器无法被系统调度器检测到,永远不会触发超时事件,等同于未启动。
预期逻辑:
- 启动定时器需完成两个核心操作:
- 从旧位置移除定时器(已有代码通过
_timer_remove 实现)。
- 计算超时时间点,并将定时器插入计时器的层级链表(跳表)。
- 当前代码缺少第2步的核心逻辑。
变量疑点:
- 声明了
row_head、tst_nr、random_nr 等用于跳表插入的变量,但后续未使用,暗示代码不完整。
解决方案
需补充定时器插入计时队列的逻辑,参考标准实现(如RT-Thread):
1. 计算超时时间点
timer->timeout_tick = rt_tick_get() + timer->init_tick;
2. 插入定时器到跳表
// 初始化跳表行头指针
for (tst_nr = 0; tst_nr < RT_TIMER_SKIP_LIST_LEVEL; tst_nr++) {
row_head[tst_nr] = &timer_list[tst_nr];
}
// 随机生成插入层级(利用static随机数)
random_nr++;
row_lvl = 0;
while ((random_nr & RT_TIMER_SKIP_LIST_MASK) == RT_TIMER_SKIP_LIST_MASK &&
row_lvl < RT_TIMER_SKIP_LIST_LEVEL - 1) {
random_nr >>= RT_TIMER_SKIP_LIST_MASK_BIT;
row_lvl++;
}
// 从高层向低层查找插入位置
for (int i = RT_TIMER_SKIP_LIST_LEVEL - 1; i >= 0; i--) {
rt_list_t *list = row_head[i];
while (list->next != &timer_list[i]) {
rt_timer_t t = rt_list_entry(list->next, struct rt_timer, row[i]);
if (t->timeout_tick > timer->timeout_tick) break; // 找到插入点
list = list->next;
}
row_head[i] = list; // 记录该层插入位置
if (i <= row_lvl) { // 在有效层级插入
rt_list_insert_after(row_head[i], &(timer->row[i]));
}
}
3. 标记定时器为激活状态
timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
修复后完整代码示例
static rt_err_t _timer_start(rt_list_t *timer_list, rt_timer_t timer) {
unsigned int row_lvl;
rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL];
unsigned int tst_nr;
static unsigned int random_nr;
/* 1. 移除旧定时器 */
_timer_remove(timer);
/* 2. 清除旧状态 */
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
/* ==== 新增:启动定时器核心逻辑 ==== */
/* 3. 计算超时时间点 */
timer->timeout_tick = rt_tick_get() + timer->init_tick;
/* 4. 初始化跳表行头 */
for (tst_nr = 0; tst_nr < RT_TIMER_SKIP_LIST_LEVEL; tst_nr++) {
row_head[tst_nr] = &timer_list[tst_nr];
}
/* 5. 随机决定插入层级 */
random_nr++;
row_lvl = 0;
while ((random_nr & RT_TIMER_SKIP_LIST_MASK) == RT_TIMER_SKIP_LIST_MASK &&
row_lvl < RT_TIMER_SKIP_LIST_LEVEL - 1) {
random_nr >>= RT_TIMER_SKIP_LIST_MASK_BIT;
row_lvl++;
}
/* 6. 从高层向低层查找插入位置 */
for (int i = RT_TIMER_SKIP_LIST_LEVEL - 1; i >= 0; i--) {
rt_list_t *list = row_head[i];
while (list->next != &timer_list[i]) {
rt_timer_t t = rt_list_entry(list->next, struct rt_timer, row[i]);
if (t->timeout_tick > timer->timeout_tick) break;
list = list->next;
}
row_head[i] = list;
/* 在有效层级插入节点 */
if (i <= row_lvl) {
rt_list_insert_after(row_head[i], &(timer->row[i]));
}
}
/* 7. 标记定时器已激活 */
timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
/* ================================ */
return RT_EOK;
}
关键注意事项
跳表算法正确性:
- 插入逻辑需确保从最高层(
RT_TIMER_SKIP_LIST_LEVEL-1)向下遍历,直到第0层。
- 每层插入位置通过比较
timeout_tick 确定(需处理溢出)。
线程安全:
- 确保调用此函数时已关闭中断或获取调度器锁(如
rt_enter_critical())。
随机层级生成:
random_nr 是静态变量,通过低位连续1的数量决定插入层级(标准跳表实现)。
性能优化:
- 跳表查找时间复杂度为平均 O(log n),优于普通链表。
验证建议
单元测试:
- 创建定时器并启动,验证
timeout_tick 计算是否正确。
- 检查定时器是否出现在跳表的对应层级链表中。
系统测试:
- 启动周期性定时器,确认超时回调函数被触发。
- 测试高频启动/停止操作的稳定性。
通过补充上述逻辑,_timer_start() 将完整实现定时器启动功能,符合预期行为。