背景
接上篇wiki
24、【OS】【Nuttx】最小系统初始化分析(3):任务调度(一)
继续分析 Ready 队列的更新
合并 Pending 队列
还是 nxsched_merge_pending,上篇wiki分析到了当前 head 任务被lock时,无法更新Ready队列。现在继续,当任务没被 lock 时,此时会遍历 Pending 队列,并逐一将 Pending 任务按优先级从高到低合并到 Ready 队列中
这里有位开发者评论:为什么不直接从 Pending 队列移除任务,然后通过 nxsched_add_readytorun 函数添加到 Ready 队列中来?
下面会分析向 Ready 队列添加任务的功能,这里个人认为没有必要,因为面向功能不一样,分开更体现单一职责的设计原则:
- nxsched_merge_pending:目的主要用于清理 Pending 队列,把 Pending 队列直接合并到 Ready 队列中,可以一些关键调度点进行,或者起一个常周期的任务,定期清理 Pending 队列,而不需要关注 Pending 队列的更新
- nxsched_add_readytorun:目的是向 Ready 队列添加一个任务,而不关注 Pending 队列的清理
将当前的 Pending 任务按优先级,在 Ready 队列中找一个合适位置塞进去(这个for循环写的是真丑…)
当插入的这个 Pending 任务前面没有任务时,意味着这个 Pending 任务的优先级最高,且当前执行的head任务可以被抢占,那么这个 Pending 任务可以直接抢占这个正在执行的任务去运行
如图所示,若当前的 Pending 任务优先级最高,会直接切换成 Running 状态
若当前的优先级不是最高,则添加到 Ready 队列中,等待执行,当前 Pending 队列遍历完后,所有的 Pending 任务已合入到 Ready 队列,此时清空 Pending 队列,返回状态
这里说下这个返回状态,当返回状态为true时,表示需要立刻切换上下文,状态为false,则不需要马上切换上下文。虽然函数接口注释已经说明,但其实该接口的设计违背了单一职责的设计原则,从接口功能来说,其主要目的是为了合并 Pending 队列,而非指示是否需要切换上下文。
将合并Pending队列和指示是否需要切换上下文分开,是更好的设计实践
向 Ready 队列添加一个任务
接下来分析上面提到的 nxsched_add_readytorun
首先看描述,首先这个接口的功能是将一个任务添加到 Ready 队列,从输入参数类型,可以看出,针对的是 blocked 任务,所以前面提到的 Revisit 注释,可以删掉了… 该接口输入对象针对的是 blocked 任务,而非 pending 任务…
如果当前执行的任务为不可抢占任务时且该任务会导致当前任务被抢占时,添加的任务会进入到 Pending 队列(Pending队列的来源)
这里的设计有点多此一举,如果当前任务不能被抢占,直接送入 Pending 队列即可,(因为后面在解锁时,会调用 nxsched_merge_pending 对 Pending 队列进行处理)这里还多判断了下 block 任务的优先级,其实可以不用,以减少程序复杂度。
同样的,这个接口承担的功能比较多,违反了单一职责原则