Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >OpenHarmony 轻内核M核源码分析系列二 数据结构-任务就绪队列

OpenHarmony 轻内核M核源码分析系列二 数据结构-任务就绪队列

原创
作者头像
小帅聊鸿蒙
发布于 2025-05-19 12:34:44
发布于 2025-05-19 12:34:44
930
举报
文章被收录于专栏:鸿蒙开发笔记鸿蒙开发笔记

在鸿蒙轻内核源码分析上一个系列,我们分析了双向循环链表的源码。本文会继续给读者介绍源码中重要的数据结构,任务基于优先级的就绪队列Priority Queue。在讲解时,会结合数据结构相关绘图,培养读者们的数据结构的平面想象能力,帮助更好的学习和理解这些数据结构的用法。

1 任务就绪队列

在任务调度模块,就绪队列是个重要的数据结构。任务创建后即进入就绪态,并放入就绪队列。在鸿蒙轻内核中,就绪队列是一个双向循环链表数组,每个数组元素就是一个链表,相同优先级的任务放入同一个链表。

任务就绪队列Priority Queue主要供内部使用,用户进行业务开发时不涉及,所以并未对外提供接口。双向循环链表数组能够更加方便的支持任务基于优先级进行调度。任务就绪队列的核心代码在kernel\src\los_task.c文件中。

1.1 任务就绪队列的定义

kernel\src\los_task.c文件中定义了和任务就绪队列相关的主要变量。

源码如下:

代码语言:shell
AI代码解释
复制
⑴ LITE_OS_SEC_BSS LOS_DL_LIST *g_losPriorityQueueList = NULL;

⑵ static LITE_OS_SEC_BSS UINT32 g_priqueueBitmap = 0;#define PRIQUEUE_PRIOR0_BIT              (UINT32)0x80000000#define OS_PRIORITY_QUEUE_PRIORITYNUM    32

其中⑴表示任务就绪队列,是一个双向链表数组,后文初始化该数组时会将数组长度设置为⑷处定义的OS_PRIORITY_QUEUE_PRIORITYNUM;⑵表示优先级位图,标识了任务就绪队列中已挂载的就绪任务所在的优先级;⑶表示优先级为0的比特位;⑷表示任务就绪队列支持的优先级个数32,所以鸿蒙轻内核优先级的取值范围为0-31,数值越小优先级越大。

优先级位图g_priqueueBitmapbit位和优先级的关系为bit=31-priority,优先级数组g_losPriorityQueueList[priority]包含了OS_PRIORITY_QUEUE_PRIORITYNUM个数组元素,每个数组元素都是一个双向链表,同一优先级的处于就绪状态的所有任务都会挂载到对应优先级的双向链表中。

示意图如下:

2 任务就绪队列操作

2.1 初始化任务就绪队列

任务就绪队列初始化函数为OsPriQueueInit(),系统初始化阶段被调用,调用路径为:main.c:main() --> kernel\src\los_init.c:LOS_KernelInit() --> kernel\src\los_task.c:OsTaskInit() --> OsPriqueueInit()

源码如下:

代码语言:shell
AI代码解释
复制
STATIC UINT32 OsPriqueueInit(VOID)
{
    UINT32 priority;
⑴  UINT32 size = OS_PRIORITY_QUEUE_PRIORITYNUM * sizeof(LOS_DL_LIST);

    g_losPriorityQueueList = (LOS_DL_LIST *)LOS_MemAlloc(m_aucSysMem0, size);
    if (g_losPriorityQueueList == NULL) {
        return LOS_NOK;
    }

    for (priority = 0; priority < OS_PRIORITY_QUEUE_PRIORITYNUM; ++priority) {
⑵      LOS_ListInit(&g_losPriorityQueueList[priority]);
    }
    return LOS_OK;
}

⑴处计算就绪队列数组需要的内存大小,然后为任务就绪队列申请内存,占用内存为OS_PRIORITY_QUEUE_PRIORITYNUM个双向链表所需要的内存大小,运行期间该内存不会释放,为系统常驻内存。⑵处代码将每一个数组元素都初始化为双向循环链表。

2.2 任务就绪队列插入

任务就绪队列插入函数为OsPriqueueEnqueue(),该函数把就绪状态的任务插入任务就绪队列的尾部。在任务就绪队列中,先调用队列头部的任务,最后调用队列尾部的任务。

源码如下:

代码语言:shell
AI代码解释
复制
STATIC VOID OsPriqueueEnqueue(LOS_DL_LIST *priqueueItem, UINT32 priority)
{if (LOS_ListEmpty(&g_losPriorityQueueList[priority])) {
⑵      g_priqueueBitmap |= (PRIQUEUE_PRIOR0_BIT >> priority);
    }

⑶  LOS_ListTailInsert(&g_losPriorityQueueList[priority], priqueueItem);
}

⑴处先判断指定优先级priority的任务就绪队列是否为空,如果为空,则在⑵处更新优先级位图,将第31-prioritybit位设置为1。⑶处把就绪状态的任务插入任务就绪队列的尾部,进行排队。

DD一下:欢迎大家关注工粽号<程序猿百晓生>,可以了解到以下知识点。
代码语言:erlang
AI代码解释
复制
`欢迎大家关注工粽号<程序猿百晓生>,可以了解到以下知识点。`
1.OpenHarmony开发基础
2.OpenHarmony北向开发环境搭建
3.鸿蒙南向开发环境的搭建
4.鸿蒙生态应用开发白皮书V2.0 & V3.0
5.鸿蒙开发面试真题(含参考答案) 
6.TypeScript入门学习手册
7.OpenHarmony 经典面试题(含参考答案)
8.OpenHarmony设备开发入门【最新版】
9.沉浸式剖析OpenHarmony源代码
10.系统定制指南
11.OpenHarmonyUboot 驱动加载流程
12.OpenHarmony构建系统--GN与子系统、部件、模块详解
13.ohos开机init启动流程
14.鸿蒙版性能优化指南
.......

2.3 从任务就绪队列中删除

从任务就绪队列中删除的函数为OsPriqueueDequeue()。任务被删除、进入suspend阻塞状态、优先级调整等场景中,都需要调用该函数把任务从任务就绪队列中删除。

源码如下:

代码语言:shell
AI代码解释
复制
STATIC VOID OsPriqueueDequeue(LOS_DL_LIST *priqueueItem)
{
    LosTaskCB *runningTask = NULL;
⑴  LOS_ListDelete(priqueueItem);

⑵  runningTask = LOS_DL_LIST_ENTRY(priqueueItem, LosTaskCB, pendList);if (LOS_ListEmpty(&g_losPriorityQueueList[runningTask->priority])) {
⑷      g_priqueueBitmap &= ~(PRIQUEUE_PRIOR0_BIT >> runningTask->priority);
    }
}

⑴把任务从任务就绪队列中删除。⑵获取被删除任务的任务控制块信息,以获取任务的优先级。删除完任务后队列可能成为空队列,所以⑶处代码判断任务就绪队列是否为空,如果为空,则需要执行⑷处代码,更新优先级位图,将第31-prioritybit位设置为0。

2.4 获取队列中的最高优先级节点

获取任务就绪队列中优先级最高的链表节点的函数为OsPriQueueTop()

源码如下:

代码语言:shell
AI代码解释
复制
STATIC LOS_DL_LIST *OsPriqueueTop(VOID)
{
    UINT32 priority;if (g_priqueueBitmap != 0) {
⑵      priority = CLZ(g_priqueueBitmap);return LOS_DL_LIST_FIRST(&g_losPriorityQueueList[priority]);
    }

    return (LOS_DL_LIST *)NULL;
}

⑴处判断优先级位图g_priqueueBitmap是否为0,如果为0则直接返回NULL,说明任务就绪队列中没有任何就绪状态的任务。 ⑵处计算g_priqueueBitmap以二进制表示时高位为0的位数,其值就是任务的优先级priority,以此方法得到的优先级就是任务就绪队列中所有优先级里最高的。然后⑶处从该优先级的队列&g_losPriorityQueueList[priority]中获取第一个链表节点,获取的就是任务就绪队列中优先级最高的任务。

2.5 获取指定优先级的就绪任务的数量

获取任务就绪队列中指定优先级的任务数量的函数为OsPriqueueSize()

源码如下:

代码语言:shell
AI代码解释
复制
STATIC UINT32 OsPriqueueSize(UINT32 priority)
{
    UINT32 itemCnt = 0;
    LOS_DL_LIST *curPQNode = (LOS_DL_LIST *)NULL;

⑴  LOS_DL_LIST_FOR_EACH(curPQNode, &g_losPriorityQueueList[priority]) {
⑵      ++itemCnt;
    }

    return itemCnt;
}

⑴处代码使用宏LOS_DL_LIST_FOR_EACH定义的for循环遍历指定优先级priority的双向链表,如果获取到新节点则表示该优先级下有一个就绪任务,然后执行⑵处代码,对计数进行加1操作,返回的结果就是指定优先级下有多少个就绪任务。


小结

掌握鸿蒙轻内核的优先级就绪队列Priority Queue这一重要的数据结构,会给进一步学习、分析鸿蒙轻内核源代码打下了基础,让后续的学习更加容易。

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力;
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识;
  • 想要获取更多完整鸿蒙最新学习知识点,可关注B站:码牛课堂;

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
OpenHarmony内核源码分析(调度队列篇) | 内核有多少个调度队列
鸿蒙内核代码中有两个源文件是关于队列的,一个是用于调度的队列,另一个是用于线程间通讯的IPC队列。
小帅聊鸿蒙
2025/03/07
730
OpenHarmony内核源码分析(调度队列篇) | 内核有多少个调度队列
OpenHarmony 轻内核M核源码分析系列三 数据结构-任务排序链表
在鸿蒙轻内核源码分析系列一和系列二,我们分析了双向循环链表、优先级就绪队列的源码。本文会继续给读者介绍鸿蒙轻内核源码中重要的数据结构:任务排序链表TaskSortLinkAttr。鸿蒙轻内核的任务排序链表,用于任务延迟到期/超时唤醒等业务场景,是一个非常重要、非常基础的数据结构。本文中所涉及的源码,以OpenHarmony LiteOS-M内核为例。
小帅聊鸿蒙
2025/05/20
770
OpenHarmony 轻内核M核源码分析系列三 数据结构-任务排序链表
OpenHarmony 轻内核M核源码分析系列九 互斥锁Mutex
多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源是非共享的临界资源,只能被独占使用。鸿蒙轻内核使用互斥锁来避免这种冲突,互斥锁是一种特殊的二值性信号量,用于实现对临界资源的独占式处理。另外,互斥锁可以解决信号量存在的优先级翻转问题。用互斥锁处理临界资源的同步访问时,如果有任务访问该资源,则互斥锁为加锁状态。此时其他任务如果想访问这个临界资源则会被阻塞,直到互斥锁被持有该锁的任务释放后,其他任务才能重新访问该公共资源,此时互斥锁再次上锁,如此确保同一时刻只有一个任务正在访问这个临界资源,保证了临界资源操作的完整性。
小帅聊鸿蒙
2025/05/23
750
OpenHarmony 轻内核M核源码分析系列一 数据结构-双向循环链表
在学习OpenHarmony鸿蒙轻内核源代码的时候,常常会遇到一些数据结构的使用。如果没有掌握它们的用法,会导致阅读源代码时很费解、很吃力。本文会给读者介绍源码中重要的数据结构,双向循环链表Doubly Linked List。在讲解时,会结合数据结构相关绘图,培养读者们的数据结构的平面想象能力,帮助更好的学习和理解这些数据结构的用法。
小帅聊鸿蒙
2025/05/19
730
OpenHarmony 轻内核M核源码分析系列一 数据结构-双向循环链表
OpenHarmony 轻内核M核源码分析系列六 任务及任务调度(2)任务模块
任务是操作系统一个重要的概念,是竞争系统资源的最小运行单元。任务可以使用或等待CPU、使用内存空间等系统资源,并独立于其它任务运行。鸿蒙轻内核的任务模块可以给用户提供多个任务,实现任务间的切换,帮助用户管理业务程序流程。本文我们来一起学习下任务模块的源代码,所涉及的源码,以OpenHarmony LiteOS-M内核为例,均可以在开源站点 https://gitee.com/openharmony/kernel_liteos_m 获取。
小帅聊鸿蒙
2025/05/21
940
OpenHarmony 轻内核M核源码分析系列十三 消息队列Queue
队列(Queue)是一种常用于任务间通信的数据结构。任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时,挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。如果将读队列和写队列的超时时间设置为0,则不会挂起任务,接口会直接返回,这就是非阻塞模式。消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用。
小帅聊鸿蒙
2025/05/26
790
OpenHarmony 轻内核M核源码分析系列十一(1) 信号量Semaphore
信号量(Semaphore)是一种实现任务间通信的机制,可以实现任务间同步或共享资源的互斥访问。一个信号量的数据结构中,通常有一个计数值,用于对有效资源数的计数,表示剩下的可被使用的共享资源数。以同步为目的的信号量和以互斥为目的的信号量在使用上存在差异。本文通过分析鸿蒙轻内核信号量模块的源码,掌握信号量使用上的差异。
小帅聊鸿蒙
2025/05/23
390
OpenHarmony内核源码分析(任务调度篇) | 任务是内核调度的单元
从系统的角度看,线程是竞争系统资源的最小运行单元。线程可以使用或等待CPU、使用内存空间等系统资源,并独立于其它线程运行。
小帅聊鸿蒙
2025/03/07
1060
谁是鸿蒙内核最重要的结构体?
结构体够简单了吧,只有前后两个指向自己的指针,但恰恰是因为太简单,所以才太不简单. 就像氢原子一样,宇宙中无处不在,占比最高,原因是因为它最简单,最稳定!
小帅聊鸿蒙
2025/03/06
560
谁是鸿蒙内核最重要的结构体?
OpenHarmony内核源码分析(进程概念篇) | 进程在管理哪些资源
官方文档最重要的一句话是进程是资源管理单元,注意是管理资源的, 资源是什么? 内存,任务,文件,信号量等等都是资源.故事篇中对进程做了一个形象的比喻(导演),负责节目(任务)的演出,负责协调节目运行时所需的各种资源.让节目能高效顺利的完成.
小帅聊鸿蒙
2025/03/12
1090
OpenHarmony 轻内核M核源码分析系列十二 事件Event
事件(Event)是一种任务间通信的机制,可用于任务间的同步。多任务环境下,任务之间往往需要同步操作,一个等待即是一个同步。事件可以提供一对多、多对多的同步操作。本文通过分析鸿蒙轻内核事件模块的源码,深入掌握事件的使用。
小帅聊鸿蒙
2025/05/26
930
OpenHarmony 轻内核A核源码分析系列七 进程管理 (1)
本文开始继续分析OpenHarmony LiteOS-A内核的源代码,接下来会分析进程和任务管理模块。本文中所涉及的源码,以OpenHarmony LiteOS-A内核为例。如果涉及开发板,则默认以hispark_taurus为例。
小帅聊鸿蒙
2025/06/06
1120
OpenHarmony 轻内核A核源码分析系列七 进程管理 (1)
鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源?
进程创建或fork时,拿到该进程控制块后进入Init状态,处于进程初始化阶段,当进程初始化完成将进程插入调度队列,此时进程进入就绪状态。
小帅聊鸿蒙
2025/03/06
770
鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源?
OpenHarmony内核源码分析(互斥锁篇) | 互斥锁比自旋锁丰满多了
图中是内核有关模块对互斥锁初始化,有文件,有内存,用消息队列等等,使用面非常的广.其实在给内核源码加注的过程中,会看到大量的自旋锁和互斥锁,它们的存在有序的保证了内核和应用程序的正常运行.是非常基础和重要的功能.
小帅聊鸿蒙
2025/03/13
1260
OpenHarmony内核源码分析(互斥锁篇) | 互斥锁比自旋锁丰满多了
鸿蒙轻内核M核源码分析系列十三(续) 消息队列QueueMail接口
之前分析过队列(Queue)的源代码,了解了队列初始化、队列创建、删除、队列读取写入等操作。队列还提供了两个接口OsQueueMailAlloc和OsQueueMailFree。队列可以和一个静态内存池关联起来,一个任务从静态内存池申请内存块时,如果申请不到,会把该任务插入到队列的内存阻塞链表中,等有其他任务释放内存时,该任务会被分配内存块。
玖柒的小窝
2021/09/17
2830
OpenHarmony内核源码分析(线程概念篇) | 是谁在不断的折腾CPU
在鸿蒙内核线程(thread)就是任务(task),也可以叫作业.线程是对外的说法,对内就叫任务.跟王二毛一样, 在公司叫你王董,回到家里还有领导,就叫二毛啊.这多亲切.在鸿蒙内核是大量的task,很少看到thread,只出现在posix层.当一个东西理解就行.
小帅聊鸿蒙
2025/03/11
1230
OpenHarmony 内核源码分析(读写锁) | 内核如何实现多读单写
读写锁 :是计算机程序的并发控制的一种同步机制,也称“共享-互斥锁”、多读者-单写者锁。读操作可并发重入,写操作是互斥的。
小帅聊鸿蒙
2025/04/02
420
OpenHarmony 轻内核A核源码分析系列三 物理内存(1)
从本篇开始,我们分析下鸿蒙轻内核A核的内存管理部分,包括物理内存、虚拟内存、虚拟映射等部分。物理内存(Physical memory)是指通过物理内存条而获得的内存空间,相对应的概念是虚拟内存(Virtual memory)。虚拟内存使得应用进程认为它拥有一个连续完整的内存地址空间,而通常是通过虚拟内存和物理内存的映射对应着多个物理内存页。本文我们先来熟悉下OpenHarmony鸿蒙轻内核提供的物理内存(Physical memory)管理模块。
小帅聊鸿蒙
2025/05/30
750
OpenHarmony 轻内核A核源码分析系列三 物理内存(1)
OpenHarmony 轻内核A核源码分析系列七 进程管理 (2)
本文先熟悉下进程管理的文件kernel\base\core\los_process.c中的内部接口,读读代码,做些记录。
小帅聊鸿蒙
2025/06/06
530
OpenHarmony 轻内核M核源码分析系列六 任务及任务调度(3)任务调度模块
调度,Schedule也称为Dispatch,是操作系统的一个重要模块,它负责选择系统要处理的下一个任务。调度模块需要协调处于就绪状态的任务对资源的竞争,按优先级策略从就绪队列中获取高优先级的任务,给予资源使用权。
小帅聊鸿蒙
2025/05/22
910
推荐阅读
OpenHarmony内核源码分析(调度队列篇) | 内核有多少个调度队列
730
OpenHarmony 轻内核M核源码分析系列三 数据结构-任务排序链表
770
OpenHarmony 轻内核M核源码分析系列九 互斥锁Mutex
750
OpenHarmony 轻内核M核源码分析系列一 数据结构-双向循环链表
730
OpenHarmony 轻内核M核源码分析系列六 任务及任务调度(2)任务模块
940
OpenHarmony 轻内核M核源码分析系列十三 消息队列Queue
790
OpenHarmony 轻内核M核源码分析系列十一(1) 信号量Semaphore
390
OpenHarmony内核源码分析(任务调度篇) | 任务是内核调度的单元
1060
谁是鸿蒙内核最重要的结构体?
560
OpenHarmony内核源码分析(进程概念篇) | 进程在管理哪些资源
1090
OpenHarmony 轻内核M核源码分析系列十二 事件Event
930
OpenHarmony 轻内核A核源码分析系列七 进程管理 (1)
1120
鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源?
770
OpenHarmony内核源码分析(互斥锁篇) | 互斥锁比自旋锁丰满多了
1260
鸿蒙轻内核M核源码分析系列十三(续) 消息队列QueueMail接口
2830
OpenHarmony内核源码分析(线程概念篇) | 是谁在不断的折腾CPU
1230
OpenHarmony 内核源码分析(读写锁) | 内核如何实现多读单写
420
OpenHarmony 轻内核A核源码分析系列三 物理内存(1)
750
OpenHarmony 轻内核A核源码分析系列七 进程管理 (2)
530
OpenHarmony 轻内核M核源码分析系列六 任务及任务调度(3)任务调度模块
910
相关推荐
OpenHarmony内核源码分析(调度队列篇) | 内核有多少个调度队列
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档