鸿蒙Hi3861学习五-Huawei LiteOS(任务管理)

news2024/11/18 17:32:59

一、任务简介

        关于任务的相关介绍,之前文章有比较详细的介绍,这里不做过多解释,可以参考如下文章:FreeRTOS学习二(任务)_t_guest的博客-CSDN博客

         而LiteOS的主要特性可以总结为如下几点:

  1. LiteOS的任务模块可以给用户提供多个任务,实现了任务之间的切换和通信,帮助用户管理业务程序流程。
  2. LiteOS中的任务是抢占式调度机制高优先级的任务可以打断低优先级任务,低优先级任务必须在高优先级任务阻塞或结束后才能得到调度,同时支持时间片轮转调度方式
  3. LiteOS的任务默认有32个优先级(0-31),最高优先级为0,最低优先级为31.

二、任务

任务状态        

        任务状态通常分为一下四种:

  • 就绪(Ready):该任务在就绪列表中,只等待CPU
  • 运行(Running):该任务正在执行
  • 阻塞(Blocked):该任务不在就绪列表中。包含任务被挂起、任务被延时、任务正在等待信号量、读写队列或等待读写事件等。
  • 退出态(Dead):任务运行结束等待系统回收资源

名词介绍

任务ID:在任务创建时通过参数返回给用户,作为任务的一个非常重要的标识

任务优先级:优先级标识任务执行的优先顺序

任务入口函数:每个新任务得到调度后将执行的函数

任务控制块TCB:每个任务都含有一个任务控制快(TCB-Task Control Block)。TCB包含了任务上下文栈指针(stack pointer)、任务状态、任务优先级、任务ID、任务名、任务栈大小等信息。TCB可以反映出每个任务的运行情况

任务栈:每个任务都拥有一个独立的栈空间,称为任务栈。

任务上下文:任务在运行过程中使用到的一些资源,如寄存器等,我们称为任务上下文。LitsOS在任务挂起的时候会将本任务的任务上下文信息,保存在自己的任务栈里面,以便任务恢复后,从栈空间中恢复挂起时的上下文信息,从而继续执行被挂起时被打断的代码。

任务切换:任务切换包含获取就绪列表中最高优先级任务、切出任务上下文保存、切入任务上下文恢复等动作。

任务状态迁移

就绪态->运行态:任务创建后进入就绪态,发生任务切换时,就绪列表中最高优先级的任务被执行,从而进入运行态,但此刻该任务依旧在就绪列表中。

运行态->阻塞态:任务运行因挂起、读信号量等待等,在就绪列表中被删除进入阻塞态。

阻塞态->就绪态(阻塞态->运行态):阻塞的任务被恢复后(任务恢复、延时时间超时、读信号量超时或读到信号量等),此时被恢复的任务就会被加入就绪列表,从而由阻塞态变成就绪态。此时如果被恢复任务的优先级高于正在运行任务的优先级,则会发生任务切换,将该任务由就绪态变成运行态。

就绪态->阻塞态:任务在就绪态被挂起,进而进入阻塞态。

运行态->就绪态:有更高优先级任务创建或恢复后,发生任务切换而进入就绪列表。

运行态->退出态:任务运行结束,内核自动将此任务删除,此时由运行态变为退出态。

阻塞态->退出态:阻塞的任务调用删除接口,任务状态由阻塞态变成退出态。

三、 实操

        LiteOS-m的内核代码是从CMSIS-RTOS2接口中封装而来。

1.什么是CMSIS-RTOS2接口

        CMSIS是Cortex微控制器软件接口标准(Cortex Microcontroller Software Interface Standard)是ARM和一些编译器厂家以及半导体厂家共同遵循的一套标准,是由ARM专门针对Cortex-M系列提出的标准。在该标准的约定下,ARM和芯片厂商会提供一些通用的API接口来访问Cortex内核以及一些专用外设,以减少更换芯片以及开发工具等移植工作所带来的金钱以及时间上的消耗。

        CMSIS-RTOS2(CMSIS-RTOS API Version 2)是Arm® Cortex®-M 处理器的通用的RTOS接口。为需要RTOS功能的软件组件提供了标准化的API。

        CMSIS-RTOS2是一个通用的API,它与底层的RTOS内核无关,写应用程序的程序员在用户代码中调用CMSIS-RTOS2 API函数,可以更方便地将应用程序从一个RTOS到另一个RTOS,使用CMSIS-RTOS2 API的中间件也可以避免很多不必要的移植工作。

        官方API参考:Main Page

         SDK中内核的源码文件在kernel/liteos_m/components/cmsis中。

2.常用函数

        osThreadNew

       函数功能

        创建一个新的任务。

        函数原型

osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)

        参数

        func:线程的回调函数

        argument:作为启动参数传递给线程函数的指针。一般为NULL

        attr:线程属性。线程的相关属性都在这里设置,包括线程堆栈大小,优先级等等。主要看osThreadAttr_t数据类型。

typedef struct {
  /** Thread name */
  const char                   *name;
  /** Thread attribute bits */
  uint32_t                 attr_bits;
  /** Memory for the thread control block */
  void                      *cb_mem;
  /** Size of the memory for the thread control block */
  uint32_t                   cb_size;
  /** Memory for the thread stack */
  void                   *stack_mem;
  /** Size of the thread stack */
  uint32_t                stack_size;
  /** Thread priority */
  osPriority_t              priority;
  /** TrustZone module of the thread */
  TZ_ModuleId_t            tz_module;
  /** Reserved */
  uint32_t                  reserved;
} osThreadAttr_t;
name

线程的名称

指向具有线程对象的可读字符串

默认值为:NULL

attr_bits

属性位,可以设置线程对象的选项。

osThreadDetached(0):在分离模式下创建线程(默认)

osThreadJoinable(1):在可连接模式下创建线程

cb_mem

内存控制块位置

指向线程控制块对象的内存位置。静态内存分配时使用

默认值:NULL(动态内存分配)

cb_size

为控制块提供的内存大小

内存块的大小与cb_mem一起传递。必须大于或等于线程控制块的大小。(静态内存分配时使用)

stack_mem

内存的堆栈位置

指向线程堆栈的内存位置的指针,必须64字节对齐。静态内存分配时使用。

默认值:NULL(动态内存分配)

stack_size

堆栈大小

由stack_mem指定的堆栈大小。即给创建的线程分配的堆栈大小

priority        

线程优先级。

默认值:osPriorityNormal(24)

注:这里的优先级与liteos的优先级不同。Liteos优先级是31最低,0最高。这里0最低,38最高

tz_module

TrustZone模块标识符

线程上下文管理标识符为线程分配上下文内存。以非安全状态运行的RTOS内核调用由头文件TZ_context.h定义的接口函数。对于根本不使用安全调用的线程,可以安全地设置为零。

reserved        

保留

默认值:0

        返回值

        线程ID,可以供其他函数调用。

        实例

    attr.name = "thread1";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 1;
    attr.priority = 25; 

    g_thread1_id  = osThreadNew((osThreadFunc_t)thread1, NULL, &attr);
    if (g_thread1_id == NULL)
    {
        LOG_E("Falied to create thread1!");
    }

        osThreadGetId

        函数功能

        获取线程ID

        函数原型

osThreadGetId

        参数

        无

        返回值

        线程ID

        实例

osThreadId_t temp_t2_id = osThreadGetId();

        osThreadGetName

        函数功能

        获取线程的名字。名字是线程在创建是设置的

        函数原型

const char *osThreadGetName(osThreadId_t thread_id)

        参数

        thread_id:线程ID。通过osThreadGetId或osThreadNew获得

        返回值

        线程的ID。错误时返回NULL

        实例

osThreadId_t temp_t2_id = osThreadGetId();
const char *temp_name = osThreadGetName(temp_t2_id);

        osThreadGetStackSize

        函数功能

        获取线程总栈大小

        函数原型

uint32_t osThreadGetStackSize(osThreadId_t thread_id)

        参数

        线程ID。通过osThreadGetId或osThreadNew获得

        返回值

        线程总栈大小

        实例

osThreadId_t temp_t2_id = osThreadGetId();
osThreadGetStackSize(temp_t2_id);

        osThreadGetStackSpace

        函数功能

        获取线程剩余栈大小

        函数原型

uint32_t osThreadGetStackSpace(osThreadId_t thread_id)

        参数

        线程ID。通过osThreadGetId或osThreadNew获得

        返回值

        线程剩余栈大小

        实例

osThreadId_t temp_t2_id = osThreadGetId();
osThreadGetStackSpace(temp_t2_id);

        osKernelGetTickCount

        函数功能

        获取系统时钟的Tick数。通常Tick数周期为1ms

        函数原型

uint32_t osKernelGetTickCount(void)

        参数

        无

        返回值

        Tick数

        实例

osKernelGetTickCount()

        osDelay

        函数功能

        线程挂起时间。

        函数原型

osStatus_t osDelay(uint32_t ticks)

        参数

        挂起ticks数。真正的挂起时间为ticks*10ms

        返回值

        osOK:正常

        osError:异常

        实例

osDelay(200);

        osDelayUntil

        函数功能

        线程挂起,直到ticks数为止。

        注:调用该函数后,线程会挂起,直到系统的ticks数,到达设置的ticks数为止。例如这里设置ticks数为1000,那么线程运行到osDelayUntil函数后会查询当前的系统ticks数,如果小于1000则挂起等待,直到系统ticks数等于1000后,才开始继续往下执行。

        函数原型

osStatus_t osDelayUntil(uint32_t ticks)

        参数

        ticks数

        返回值

        osOK:正常

        osError:异常

        实例

osDelayUntil(1000);

        osThreadTerminate

        函数功能

        删除线程。线程终止后,所有的资源都会返回到系统

        注:该函数不能在中断服务中调用

        函数原型

osStatus_t osThreadTerminate(osThreadId_t thread_id)

        参数

        线程ID

        返回值

        osOK:成功

        其他值:异常。含义参考如下:

typedef enum {
  /** Operation completed successfully */
  osOK                      =  0,
  /** Unspecified error */
  osError                   = -1,
  /** Timeout */
  osErrorTimeout            = -2,
  /** Resource error */
  osErrorResource           = -3,
  /** Incorrect parameter */
  osErrorParameter          = -4,
  /** Insufficient memory */
  osErrorNoMemory           = -5,
  /** Service interruption */
  osErrorISR                = -6,
  /** Reserved. It is used to prevent the compiler from optimizing enumerations. */
  osStatusReserved          = 0x7FFFFFFF
} osStatus_t;

        实例

osThreadId_t temp_t2_id = osThreadGetId();
osStatus_t ret = osThreadTerminate(temp_t2_id);

        

四、综合实例

        这里我们创建两个线程,并且分别打印两个线程的栈大小、名字、剩余栈大小。且任务一使用创建时osThreadNew返回的任务ID,而任务2使用osThreadGetId获取的任务ID。看看效果是否相同。

#define LOG_I(fmt, args...)   printf("<%8ld> - [APP]:"fmt"\r\n",osKernelGetTickCount(),##args);

#define LOG_E(fmt, args...)   printf("<%8ld>-[APP_ERR]>>>>>>>>>>>>:"fmt"\r\n",osKernelGetTickCount(), ##args);

osThreadId_t g_thread1_id = NULL;
osThreadId_t g_thread2_id = NULL;

/*****任务一*****/
void thread1(void)
{
    LOG_I("thread 1 start");
    const char *temp_name = osThreadGetName(g_thread1_id);
    int sum = 0;
    osDelayUntil(1000);

    while (1)
    {
        LOG_I("this is Thread 1,name:[%s],thread stack size:[%ld],left stack:[%ld],sum:%d", temp_name,osThreadGetStackSize(g_thread1_id),osThreadGetStackSpace(g_thread1_id),sum);
        osDelay(100);
        if(sum++ > 10)
            break;
    }
    LOG_I("thread 1 break");
    osThreadTerminate(g_thread1_id);
}


/*****任务二*****/
void thread2(void)
{
    LOG_I("thread 2 start");
    osThreadId_t temp_t2_id = osThreadGetId();
    const char *temp_name = osThreadGetName(temp_t2_id);
    while (1)
    {
         LOG_I("this is Thread 2,name:[%s],thread stack size:[%ld],left stack:[%ld]", temp_name,osThreadGetStackSize(temp_t2_id),osThreadGetStackSpace(temp_t2_id));
        osDelay(100);
    }
    LOG_I("thread 2 end");
}


void Hello_World(void)
{
    osThreadAttr_t attr;

    LOG_I("hello!!!!!!!!!!!!!!!!!!!!!!!!!");

    attr.name = "thread1";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 1;
    attr.priority = 25; 

    g_thread1_id  = osThreadNew((osThreadFunc_t)thread1, NULL, &attr);
    if (g_thread1_id == NULL)
    {
        LOG_E("Falied to create thread1!");
    }
    else
    {
        LOG_I("thread1 id:0x%.8x",*(uint32_t *)(g_thread1_id));
    }

    attr.name = "thread2";
    attr.stack_size = 1024 * 2;

    g_thread2_id = osThreadNew((osThreadFunc_t)thread2, NULL, &attr);
    if (g_thread2_id == NULL)
    {
        LOG_E("Falied to create thread2!");
    }
    else
    {
        LOG_I("thread2 id:0x%.8x",*(uint32_t *)(g_thread2_id));
    }  
}

SYS_RUN(Hello_World);

        从结果可以看到如下几点信息:

  1. 线程1在开始运行后,遇到了osDelayUntil,直接挂起。等到系统ticks到达1000后才继续往下运行。
  2. 线程1中使用的线程ID是创建线程时osThreadNew返回的。而线程2中使用的线程ID是通过osThreadGetId函数获取的。都能达到预期的效果。
  3. osThreadGetStackSize和osThreadGetStackSpace会分别打印出栈总大小和剩余栈大小。
  4. 线程1在运行10次后,就删除了自身,并且释放了所有的资源。

参考链接:

CMSIS-RTOS2 文档翻译 之 参考(CMSIS-RTOS2 API 之 线程管理) - 爱码网

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/492515.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一个文章学会使用Git

GIT版本控制系统 版本控制系统 : ​ 1.记录历史版本信息 (记录每一次修改的记录) ​ 2.方便团队相互之间协作开发 ​ … 常用的版本控制系统 cvs / svn : 集中式版本控制系统git : 分布式版本控制系统 svn git GIT工作原理 工作区 : 我们能看到的&#xff0c;并且用来写代码的…

nodejs的安装以及Dos的命令

1.0 nodeJS nodejs是基于谷歌v8引擎的执行环境&#xff0c;他没有BOM、DOM nodeJS安装 找官网 ->下载 -> 傻瓜式下一步 -> win键 r -> 输入cmd 进入dos操作命令 -> node -v 查看版本 1.1 DOS 命令【掌握】 进入指定文件夹 cd 文件目录 退出到上一层 cd .…

112.【Vue-细刷-03】

Vue-03 (二十)、过渡和动画1.过渡案列_原生实现2.过渡案列_Vue实现3.动画案列_Vue实现 (1)4.动画案列_Vue实现(2)5.Vue实现时间格式化6.Vue实现过滤器7.Vue常用内置指令 (二十一)、Vue的自定义指令1.自定义非内嵌指令&#xff08;不保留h2中的原有text&#xff09;2.自定义非内…

在线教育机构视频加密防下载和防盗用的方法有哪些可以借鉴

阿酷TONY / 原创 / 2023-5-5 / 长沙 在线教育机构防止视频被盗用和视频被下载&#xff0c;可以采取以下措施&#xff0c;一共10条&#xff0c;总有一条适用于您吧&#xff0c;收藏一下吧~~~~~ 1.VRM分片错序视频加密 2.Html5全链路视频加密 3.用户ID跑马灯 4.数字化动态水印 …

【科普帖】晶振 OCXO、VCXO、TCXO、VC-TCXO、DCXO、SPXO区别

一、前言 晶体振荡器用作频率基准&#xff0c;以生成非常稳定的频率源。它用于许多应用中&#xff0c;如频率合成器&#xff0c;本地振荡器&#xff0c;并在调制解调器和其他电路中提供稳定的时钟。 晶体输出频率漂移主要受温度、电源电压和老化的影响。其中温度变化是最为重要…

PS VR创始成员:瑕不掩瑜,PS VR2是跨世代的飞跃

今年2月&#xff0c;索尼次世代VR头显PS VR2正式发售&#xff0c;这款立项近7年的产品受到了游戏玩家和从业者广泛关注&#xff0c;市面上也有很多种不同的测评报告。PS VR项目创始成员、前索尼沉浸式体验专家、高级VR游戏设计师Jed Ashforth也发表了自己对于该头显的一些看法&…

Verilog概述一:Verilog HDL和 VHDL详细对比

当前比较流行的硬件设计语言有两种&#xff0c;即 VHDL 与 Verilog HDL&#xff0c;两者各有优劣&#xff0c;也各有相当多的拥护者。 VerilogHDL和VHDL都是完备的HDL设计和验证语言&#xff0c;具有完整的设计方法和设计规范。 何为HDL HDL&#xff08;hardware descriptio…

Go type关键字定义新类型和类型别名的区别

type关键字再定义类型和类型别名有很大的区别&#xff0c;前者是新定义一个数据类型&#xff0c;后者是对类型的重命名。 type NewString stringtype OldString stringtype NewString string声明了一个NewString类型&#xff0c;和string具有完全一致的数据结构&#xff0c;确…

【Linux】usb游戏手柄测试、编程

1、简述 在ubuntu18.04下使用usb游戏手柄,之前联系客服,客服回答不清楚是否支持linux,因此采购一款北通蝙蝠2的手柄来测试 2、测试 2.1 测试环境 系统:Ubuntu18.04 正常电脑系统ubuntu中都是自带手柄驱动的joystick,即内核配置已添加选项:Joysticks interface和Joys…

vue - 常见的移动端适配方案

移动端适配方案 rem适配原理方案1&#xff1a;rem媒体查询方案2&#xff1a;jsrem方案3&#xff1a;vwrem&#xff08;不用查询屏幕宽度&#xff09; 移动端适配经常使用的就是 rem; 主要有以下几种方案&#xff1a; 1&#xff1a;rem 媒体查询&#xff08;media&#xff09; …

Springboot(二):配置文件读取

1.1引入依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><a…

一目了然凉哥为大家倾力打造的付费专栏

写在前面 大家好&#xff0c;我是几何心凉&#xff0c;欢迎来到我的付费专栏系列&#xff0c;本专栏将深入介绍 Vue 3 和 Vite&#xff0c;以及如何在 TypeScript 的帮助下构建现代化的 Web 应用程序。 Vue 是一个流行的 JavaScript 框架&#xff0c;它允许开发人员构建高性能…

Java之多线程初阶

目录 一.进程和线程 1.什么是进程 2.并发,并行和串行 3.线程和多线程 4.进程和线程的区别(重点) 5.多线程的优点 6.多线程的缺点 二.线程的创建 1.继承Thread类 2.实现Runnable接口重写run()方法 3.通过匿名内部类的方式创建Thread和实现Runnable 4.通过Lambda表达式…

金豺(GJO)优化算法、matlab代码实现以及与PSO、GWO、SO算法比对

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言1 算法原理2 算法步骤2.1 初始化种群2.2 搜索猎物(全局搜索)2.3 包围和围捕猎物&#xff08;局部搜索&#xff09;2.4 从全局搜索转向局部搜索 3 算法流程图4 m…

(22)目标检测算法之 yolov8模型导出总结

yolov8模型导出总结 不断更新中… 几种部署情况: onnxxmlengine官网说明:https://github.com/ultralytics/ultralytics/blob/main/docs/modes/export.md导出参数: onnx 参数解析format: 导出的模型形式:onnx xml engine ... imgsz: 设置模型的输入尺寸大小,默认640*640 ke…

记录一次docker镜像迁移过程

1.在母本服务器上查看要复刻的docker镜像。 sv800:build 作为docker镜像源[repository:tag],使用docker save 指令提出docker镜像包rk3588.tar docker save -o rk3588.tar sv800:build 2.在新环境下加载docker镜像包&#xff0c;预先安装docker指令工具 docker load -i rk35…

OCT图像中的多尺度无监督视网膜水肿区域分割

文章目录 Multiscale Unsupervised Retinal Edema Area Segmentation in OCT Images摘要本文方法原始的DCCS无监督图像聚类Pseudo-Mask-Guided Pixel-Wise Segmentation 实验结果 Multiscale Unsupervised Retinal Edema Area Segmentation in OCT Images 摘要 提出了一种新的…

STM32F051K8U6按键中断实例

引言 最近要开始做毕设了&#xff0c;准备用STM32做一个平衡小车&#xff0c;好久没做过STM32的裸机项目了&#xff0c;做几个项目练练手&#xff0c;复习一下。本例程使用STM32CubeMX配套hal库来实现按键中断和串口中断。芯片用的是STM32F051K8U6。 一、按键中断 &#xff0…

iproute2和流量控制(ip和tc工具)---iproute2/ip/tc/qdisc实现Linux下的QoS控制

iproute2是一个软件包&#xff0c;这个软件包包含了多种用于高级路由&#xff0c;隧道和流量控制配置工具软件。 iproute2提供了Linux内核对QoS的实现&#xff0c;你可以在以下网站中找到英文原版的信息osdl.org和lartc.org。这些工具软件中&#xff0c;最重要的当数ip和tc这二…

【Flutter从入门到入坑之五】你真的会使用 Widget 中的 State 吗?

【Flutter从入门到入坑】Flutter 知识体系 【Flutter从入门到入坑之一】Flutter 介绍及安装使用 【Flutter从入门到入坑之二】Dart语言基础概述 【Flutter从入门到入坑之三】Flutter 是如何工作的 【Flutter从入门到入坑之四】构建Flutter界面的基石——Widget State 前沿UI 编…