0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

LiteOS-M内核队列的关键数据结构及关键算法

2KHh_gh_15d2f06 来源:深开鸿 作者:蒋卫峰 2022-06-14 11:01 次阅读

一、前言

随着数字经济的发展,作为数字基础设施根技术的操作系统成为数字变革的关键力量,OpenAtom OpenHarmony(以下简称“OpenHarmony”) 以泛智能终端数字为底座支撑着千行百业的产业生态。

构建开源生态,需要让开发者先用起来,本文希望通过分享 OpenHarmony 的 LiteOS-M 内核对象队列的算法详解,让大家对这一算法有更加清晰的认识。 OpenHarmony 当前分为以下几种系统类型:轻量系统 、小型系统、标准系统。针对不同量级的系统,分别使用了不同形态的内核。在轻量系统上,可以选择 LiteOS-M;在小型系统和标准系统上,可以选用 LiteOS-A;在标准系统上,可以选用 Linux。 在轻小型系统中,OpenHarmony 所使用的内核为 LiteOS,在标准系统中使用 Linux。LiteOS-M 在面向 loT 领域构建了一款轻量级物联网操作系统内核,嵌入式从业者如果能更好地掌握内核相关的知识,就能在未来做研发或者定制产品的时候独当一面。

二、关键数据结构

首先关注队列的关键数据结构 LosQueueCB,有了这个数据,才能理解队列是如何工作的:
typedefstruct{    UINT8 *queue;      /**< Pointer to a queue handle */    UINT16 queueState; /**< Queue state */    UINT16 queueLen;   /**< Queue length */    UINT16 queueSize;  /**< Node size */    UINT16 queueID;    /**< queueID */    UINT16 queueHead;  /**< Node head */    UINT16 queueTail;  /**< Node tail */    UINT16 readWriteableCnt[OS_READWRITE_LEN]; /**< Count of readable or writable resources, 0:readable, 1:writable */    LOS_DL_LIST readWriteList[OS_READWRITE_LEN]; /**< Pointer to the linked list to be read or written,                                                      0:readlist, 1:writelist */    LOS_DL_LIST memList; /**< Pointer to the memory linked list */}LosQueueCB;

*queue:指向消息节点内存区域,创建队列时按照消息节点个数乘每个节点大小从动态内存池中申请一片空间。

queueState:队列状态,表明队列控制块是否被使用,有 OS_QUEUE_INUSED和OS_QUEUE_UNUSED 两种状态。

queueLen:消息节点个数,表示该消息队列最大可存储多少个消息。

queueSize:每个消息节点大小,表示队列每个消息可存储信息的大小。

queueID:消息 ID,通过它来操作队列。

消息节点按照循环队列的方式访问,队列中的每个节点以数组下标表示,下面的成员与消息节点循环队列有关:

queueHead:循环队列的头部。

queueTail:循环队列的尾部。

readWriteableCnt[OS_QUEUE_WRITE]:消息节点循环队列中可写的消息个数,为 0 表示循环队列为满,等于 queueLen 表示循环队列为空。

readWriteableCnt[OS_QUEUE_READ]:消息节点循环队列中可读的消息个数,为 0 表示循环队列为空,等于 queueLen 表示消息队列为满。

readWriteList[OS_QUEUE_WRITE]:写消息阻塞链表,链接因消息队列满而无法写入时需要挂起的 TASK。

readWriteList[OS_QUEUE_READ]:读消息阻塞链表,链接因消息队列空而无法读取时需要挂起的 TASK。

memList:申请内存块阻塞链表,链接因申请某一静态内存池中的内存块失败而需要挂起的 TASK。

注意:在老的版本中,readWriteableCnt 和 readWriteList 拆分为 4 个变量,新版本用宏定义合并,OS_QUEUE_READ 标识是读操作,OS_QUEUE_WRITE 标识为写操作。从中可看到代码的微妙之处,0 的含义和 queueLen 对于读写是统一的,内核开发者不断使用抽象手段来优化内核。

三、关键算法

队列的算法和 FIFO、FILO 有关,今天先给大家介绍 FIFO 算法。

百度定义:FIFO(First Input First Output),即先进先出队列。例如,在超市购物之后我们会到收银台排队结账,看着前面的客户一个个离开,这就是一种先进先出机制,先排队的客户先行结账离开。

那么 OpenHarmony 的队列如何实现这个算法?

3.1 FIFO算法之入队列

第一步:队列初始化

由于 LOS_QueueCreate 函数太长,便只截取关键函数 LOS_QueueCreate。

LITE_OS_SEC_TEXT_INITUINT32LOS_QueueCreate(CHAR*queueName,                                         UINT16 len,                                         UINT32 *queueID,                                         UINT32 flags,                                         UINT16 maxMsgSize){    LosQueueCB *queueCB = NULL;    UINT32 intSave;    LOS_DL_LIST *unusedQueue = NULL;    UINT8 *queue = NULL;    UINT16 msgSize;    ...    queue = (UINT8 *)LOS_MemAlloc(m_aucSysMem0, len * msgSize);    ...    queueCB->queueLen = len;    queueCB->queueSize = msgSize;    queueCB->queue = queue;    queueCB->queueState = OS_QUEUE_INUSED;    queueCB->readWriteableCnt[OS_QUEUE_READ] = 0;    queueCB->readWriteableCnt[OS_QUEUE_WRITE] = len;    queueCB->queueHead = 0;    queueCB->queueTail = 0;    LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_READ]);    LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_WRITE]);    LOS_ListInit(&queueCB->memList);    LOS_IntRestore(intSave);
    *queueID = queueCB->queueID;    OsHookCall(LOS_HOOK_TYPE_QUEUE_CREATE, queueCB);
    return LOS_OK;}

数据结构是支撑算法的灵魂,内核对象的队列控制结构 LosQueueCB 通过 queue 指针来指向具体队列的内容,队列分配了 queueLen 个消息,每个消息的大小为 queueSize,与此同时头指针和尾指针不约而同初始化为 0。

第二步:第一个消息入队列

生产者通过队列来传递信息,这个生产者可以是形形色色的各个任务,产生一个队列后,任务就迫不及待的需要放置消息,选择 FIFO 还是 FILO?这一次我们选择了 FIFO。

下图是 FIFO 插入第一个数据后的内存形态。

d441fbba-e72b-11ec-ba43-dac502259ad0.png

OpenHarmony 作为一个开源系统,在下面的代码中很好地体现了这个操作:

staticINLINEVOIDOsQueueBufferOperate(LosQueueCB*queueCB,UINT32operateType,                                                            VOID *bufferAddr, UINT32 *bufferSize){    UINT8 *queueNode = NULL;    UINT32 msgDataSize;    UINT16 queuePosition;    errno_t rc;
    /* get the queue position */    switch (OS_QUEUE_OPERATE_GET(operateType)) {        case OS_QUEUE_READ_HEAD:            queuePosition = queueCB->queueHead;            ((queueCB->queueHead + 1) == queueCB->queueLen) ? (queueCB->queueHead = 0) : (queueCB->queueHead++);            break;
        case OS_QUEUE_WRITE_HEAD:            (queueCB->queueHead == 0) ? (queueCB->queueHead = (queueCB->queueLen - 1)) : (--queueCB->queueHead);            queuePosition = queueCB->queueHead;            break;
        case OS_QUEUE_WRITE_TAIL:            queuePosition = queueCB->queueTail;            ((queueCB->queueTail + 1) == queueCB->queueLen) ? (queueCB->queueTail = 0) : (queueCB->queueTail++);            break;    ...}

OsQueueBufferOperate 是队列内存的核心操作函数,FIFO 算法本质是往队列的尾处添加数据,代码抽象为 OS_QUEUE_WRITE_TAIL 操作,请注意队列是个循环队列,插入数据后移动 tail 这个“尾巴”指针要尤为小心,在最后一个物理空间用完成后需要移到队列头部,这就是环形队列的“循环大法”。

如何判断最后一个物理空间已经用完?(queueCB->queueTail + 1) == queueCB->queueLen)C 语言语句很好地解释了这个疑问。queueLen 是队列物理空间的边界值,如果下一个消息已经指到这个边界值,那么内核必须让它回到原位,即 queueCB->queueTail = 0,不然可能会出现“内存越界”的问题,可能会造成机毁物亡。因为 OpenHarmony 应用在各个领域,如果是自动化驾驶领域那么造成的后果非常严重。

第三步:继续生产数据

接下来,再来一些图片示例:

d46978b6-e72b-11ec-ba43-dac502259ad0.png

第四步:生产数据结束

生产者生产了四个消息后就结束了。

d4bca324-e72b-11ec-ba43-dac502259ad0.png

3.2 FIFO算法之出队列

步:队列第一个消息

d4e48736-e72b-11ec-ba43-dac502259ad0.png

如上图所示我们回顾下入队列的步骤,知道了每个消息的入队顺序,于是第一个消息被消费后:

d50fafa6-e72b-11ec-ba43-dac502259ad0.png

在生产消息过程中我们已经提到 OsQueueBufferOperate 这个函数,我们回顾关键代码:

/*getthequeueposition*/switch (OS_QUEUE_OPERATE_GET(operateType)) {    case OS_QUEUE_READ_HEAD:        queuePosition = queueCB->queueHead;        ((queueCB->queueHead + 1) == queueCB->queueLen) ? (queueCB->queueHead = 0) : (queueCB->queueHead++);        break;

queueHead 就是我们的头指针,它的移动也面临着生产过程相同的问题,在最后一个物理空间用完成后需要移到队列的头部。OS_QUEUE_READ_HEAD 是出队列的关键处理,解决了 queueHead 头指针如何移动的问题。

第二步:继续消费

d571ad32-e72b-11ec-ba43-dac502259ad0.png

第三步:消费完毕

最后一个消息也消失了,head指针和tail指针均移动到下图的位置,此时队列为空。

d5a737b8-e72b-11ec-ba43-dac502259ad0.png

四、总结

本文主要介绍了 OpenHarmony 内核对象队列的算法之 FIFO,在后续的篇章中将给大家介绍内核对象队列另外一种算法——FILO。希望通过这篇文章,可以让开发者们对于目前 OpenHarmony LiteOS-M 内核队列算法有了更全面的概念。

当然队列算法也不远远如此,linux 标准内核有加权队列等更复杂的算法。但是“他山之石,可以攻玉”,技术万变不离其宗,掌握了 FIFO 的细节有助于工程师设计其它队列算法,也能够把更多更新的技术带入到 OpenHarmony 社区,繁荣开源生态。

原文标题:OpenHarmony——内核对象队列之算法详解(上)

文章出处:【微信公众号:深开鸿】欢迎添加关注!文章转载请注明出处。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内核
    +关注

    关注

    3

    文章

    1309

    浏览量

    39843
  • 算法
    +关注

    关注

    23

    文章

    4453

    浏览量

    90746
  • Linux
    +关注

    关注

    87

    文章

    10988

    浏览量

    206724
  • OpenHarmony
    +关注

    关注

    23

    文章

    3262

    浏览量

    15159

原文标题:OpenHarmony——内核对象队列之算法详解(上)

文章出处:【微信号:gh_15d2f062a168,微信公众号:深开鸿】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    鸿蒙是一套庞大的体系,底层支持很多内核吧?liteos-m, liteos-a,linux 都支持?

    大家都知道鸿蒙是一套庞大的体系,那么底层应该支持很多内核吧?liteos-m, liteos-a,linux 都支持吗?
    发表于 10-10 10:08

    芯来科技RISC-V处理器支持鸿蒙LiteOS-M内核

    使用芯来LiteOS-M内核仓库链接如下:https://gitee.com/riscv-mcu/kernel_liteos_m/tree/dev_nuclei/仓库内整体文件结构直观
    发表于 04-08 13:59

    OpenHarmony LiteOS-M内核概述

    内核概述内核简介OpenHarmony LiteOS-M内核是面向IoT领域构建的轻量级物联网操作系统内核,具有小体积、低功耗、高性能的特点
    发表于 05-11 19:10

    请问Hi3861用的liteOS-m为啥要固化到ROM中?

    请问谁知道Hi3861用的liteOS-m为啥要固化到ROM中,另外固化到ROM中的逻辑是什么,如果市场上采购3861的芯片 是不是都已经固化好了liteOS-m内核 谢谢
    发表于 06-16 10:59

    如何在RK2206开发板上使用鸿蒙LiteOS-M内核接口进行队列编程开发

    实验内容本例程演示如何在小凌派-RK2206开发板上使用鸿蒙LiteOS-M内核接口,进行队列编程开发。例程创建一个队列,两个任务;任务1调用写队列
    发表于 08-08 15:17

    OpenHarmony:内核对象队列算法详解(下)

    嵌入式领域的开发工作中,无论是自研还是移植系统,均绕不开内核,开发者只有掌握内核的相关知识,才能更好地深耕物联网产品领域。OpenHarmony LiteOS-M内核对象
    发表于 08-09 10:25

    OpenHarmony:内核对象队列算法详解(上)

    百业的产业生态。构建开源生态,需要让开发者先用起来,本文希望通过分享 OpenHarmony 的 LiteOS-M 内核对象队列算法详解,让大家对这一
    发表于 08-09 10:29

    OpenHarmony——内核对象队列算法详解(下)

    OpenHarmony——内核对象队列算法详解(下)前言OpenAtom OpenHarmony(以下简称“OpenHarmony”) LiteOS-M
    发表于 08-09 16:16

    每日推荐 | 鸿蒙IPC开发板免费试用,OpenHarmony内核对象队列算法详解

    贴评论区进行申请就能获得试用机会,大家冲鸭~3、OpenHarmony:内核对象队列算法详解(上)推荐理由:本文希望通过分享 OpenHarmony 的 LiteOS-M
    发表于 08-10 10:26

    OpenHarmony——内核IPC机制数据结构解析

    制涉及到哪些关键数据结构?这些数据结构又是如何工作的?接下来我将从队列、事件、互斥锁、信号量几个内核对象出发,为大家讲解
    发表于 09-05 11:02

    OpenHarmony——内核IPC机制数据结构解析

    制涉及到哪些关键数据结构?这些数据结构又是如何工作的?接下来我将从队列、事件、互斥锁、信号量几个内核对象出发,为大家讲解
    发表于 09-08 11:44

    鸿蒙liteos-m移植

    最近在研究鸿蒙liteos-m的移植,打算弄一块板移植一下,这款正适合,512k flash,128k ram.100m时钟,还有各种丰富的外设资源。
    发表于 10-27 21:17

    芯来科技RISC-V处理器将支持鸿蒙LiteOS-M内核

    芯来科技为方便客户进行基于鸿蒙生态的RISC-V软件开发,在Nuclei RISC-V 32位处理器上移植并适配了鸿蒙LiteOS-M内核。 目前该内核已可支持Nuclei Demo SoC
    的头像 发表于 04-09 15:20 3773次阅读
    芯来科技RISC-V处理器将支持鸿蒙<b class='flag-5'>LiteOS-M</b><b class='flag-5'>内核</b>

    Hi3861芯片开发板LiteOS-M的启动流程

    OpenHarmony作为一款万物互联的操作系统,覆盖了从嵌入式实时物联网操作系统到移动操作系统的全覆盖,其中内核包括LiteOS-MLiteOS-A和Linux。LiteOS-M
    的头像 发表于 08-12 11:45 1811次阅读

    Liteos-a内核工作队列的实现原理分析及经验总结——芯海科技PPG芯片CS1262接入OpenHarmony实战

    摘要OpenHarmony系统中使用了liteos-mliteos-a、linux三种内核,工作队列是linux内核引入的一种异步处理机制
    的头像 发表于 04-26 09:26 1337次阅读
    <b class='flag-5'>Liteos</b>-a<b class='flag-5'>内核</b>工作<b class='flag-5'>队列</b>的实现原理分析及经验总结——芯海科技PPG芯片CS1262接入OpenHarmony实战