鸿蒙内核源码注释中文版 < Gitee仓 | CSDN仓 | Github仓 | Coding仓 >精读内核源码,中文注解分析,深挖地基工程,构建底层网图,四大码仓每日同步更新node
鸿蒙源码分析系列篇 < CSDN | OSCHINA | WeHarmony | 公众号 >问答式导读,生活式比喻,表格化说明,图形化展现,主流站点每日同步更新编程
谁是鸿蒙内核最重要的结构体?
答案必定是: LOS_DL_LIST(双向链表),它长这样.数组
typedef struct LOS_DL_LIST {//双向链表,内核最重要结构体 struct LOS_DL_LIST *pstPrev; /**< Current node's pointer to the previous node *///前驱节点(左手) struct LOS_DL_LIST *pstNext; /**< Current node's pointer to the next node *///后继节点(右手) } LOS_DL_LIST;
结构体够简单了吧,只有先后两个指向本身的指针,但偏偏是由于太简单,因此才太不简单. 就像氢原子同样,宇宙中无处不在,占比最高,缘由是由于它最简单,最稳定!数据结构
内核的各自模块都能看到双向链表的身影,下图是各处初始化双向链表的操做,由于太多了,只截取了部分:函数
不少人问图怎么来的, source insight 4.0 是阅读大型C/C++工程的必备工具,要用4.0不然中文有乱码.工具
能够豪不夸张的说理解LOS_DL_LIST及相关函数是读懂鸿蒙内核的关键。先后指针(注者后续将比喻成一对左右触手)灵活的指挥着系统精准的运行,越是深刻分析内核源码,越能感觉到内核开发者对LOS_DL_LIST非凡的驾驭能力,笔者仿佛看到了无数双手先后相连,拉起了一个个双向循环链表,把指针的高效能运用到了极致,这也许就是编程的艺术吧!这么重要的结构体仍是需详细讲解一下.源码分析
基本概念
双向链表是指含有往前和日后两个方向的链表,即每一个结点中除存放下一个节点指针外,还增长一个指向其前一个节点的指针。其头指针head是惟一肯定的。从双向链表中的任意一个结点开始,均可以很方便地访问它的前驱结点和后继结点,这种数据结构形式使得双向链表在查找时更加方便,特别是大量数据的遍历。因为双向链表具备对称性,能方便地完成各类插入、删除等操做,但须要注意先后方向的操做。this
功能接口
鸿蒙系统中的双向链表模块为用户提供下面几个接口。spa
请结合下面的代码和图去理解双向链表,无论花多少时间,必定要理解它的插入/删除动做, 不然后续内容将无从谈起.线程
//将指定节点初始化为双向链表节点 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list) { list->pstNext = list; list->pstPrev = list; } //将指定节点挂到双向链表头部 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node) { node->pstNext = list->pstNext; node->pstPrev = list; list->pstNext->pstPrev = node; list->pstNext = node; } //将指定节点从链表中删除,本身把本身摘掉 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node) { node->pstNext->pstPrev = node->pstPrev; node->pstPrev->pstNext = node->pstNext; node->pstNext = NULL; node->pstPrev = NULL; }
具体用法
举例 ProcessCB(进程控制块)是描述一个进程的全部信息,其中用到了 8个双向链表,这简直比章鱼还牛逼,章鱼也才四双触手,但进程有8双(16只)触手.
typedef struct ProcessCB { LOS_DL_LIST pendList; /**< Block list to which the process belongs */ //进程所属的阻塞列表,若是因拿锁失败,就由此节点挂到等锁链表上 LOS_DL_LIST childrenList; /**< my children process list */ //孩子进程都挂到这里,造成双循环链表 LOS_DL_LIST exitChildList; /**< my exit children process list */ //那些要退出孩子进程挂到这里,白发人送黑发人。 LOS_DL_LIST siblingList; /**< linkage in my parent's children list */ //兄弟进程链表, 56个民族是一家,来自同一个父进程. ProcessGroup *group; /**< Process group to which a process belongs */ //所属进程组 LOS_DL_LIST subordinateGroupList; /**< linkage in my group list */ //进程是组长时,有哪些组员进程 UINT32 threadGroupID; /**< Which thread group , is the main thread ID of the process */ //哪一个线程组是进程的主线程ID UINT32 threadScheduleMap; /**< The scheduling bitmap table for the thread group of the process */ //进程的各线程调度位图 LOS_DL_LIST threadSiblingList; /**< List of threads under this process *///进程的线程(任务)列表 LOS_DL_LIST threadPriQueueList[OS_PRIORITY_QUEUE_NUM]; /**< The process's thread group schedules the priority hash table */ //进程的线程组调度优先级哈希表 volatile UINT32 threadNumber; /**< Number of threads alive under this process */ //此进程下的活动线程数 UINT32 threadCount; /**< Total number of threads created under this process */ //在此进程下建立的线程总数 LOS_DL_LIST waitList; /**< The process holds the waitLits to support wait/waitpid *///进程持有等待链表以支持wait/waitpid } LosProcessCB;
看个简单点的 pendList表示这个进程中全部被阻塞的任务(task)都会挂到这个链表上管理. 任务阻塞的缘由不少,多是申请互斥锁失败,可能等待事件读消息队列,还可能开了一个定时任务等等.
再来看一个复杂点的 threadPriQueueList,这又是干吗的?从名字能够看出来是线程的队列链表,在鸿蒙内核线程就是任务(task),任务分等了32个优先级,同级的任务放在同一个双向链表中, 32级就是32个双向链表,因此是个链表数组,每条链表中存放的是已就绪等待被调度的任务.
双向链表是内核最重要的结构体,精读内核的路上它会反复的映入你的眼帘,理解它是理解内存运做的关键所在!
做者:weharmony
想了解更多内容,请访问: 51CTO和华为官方战略合做共建的鸿蒙技术社区https://harmonyos.51cto.com/