RT-Thread线程管理(使用篇)

news2024/11/16 15:42:44

layout: post
title: “RT-Thread线程管理”
date: 2024-1-26 15:39:08 +0800
tags: RT-Thread


线程管理(使用篇)

之后会做源码分析

线程是任务的载体,是RTT中最基本的调度单位。

线程执行时的运行环境称为上下文,具体来说就是各个变量和数据,包括所有的寄存器变量、堆栈、内存信息等。

管理的特点

RT-Thread 线程管理的主要功能是对线程进行管理和调度,系统中总共存在两类线程,分别是系统线程和用户线程

这两类线程都会从内核对象容器中分配线程对象,当线程被删除时,也会被从对象容器中删除。

RT-Thread 的线程调度器是抢占式的,主要的工作就是从就绪线程列表中查找最高优先级线程,保证最高优先级的线程能够被运行,最高优先级的任务一旦就绪,总能得到 CPU 的使用权。

struct rt_thread
{
    /* rt object */
    char        name[RT_NAME_MAX];                      /**< the name of thread 名字*/
    rt_uint8_t  type;                                   /**< type of object 类型*/
    rt_uint8_t  flags;                                  /**< thread's flags 标志位*/

#ifdef RT_USING_MODULE
    void       *module_id;                              /**< id of application module */
#endif

    rt_list_t   list;                                   /**< the object list 对象列表*/
    rt_list_t   tlist;                                  /**< the thread list 线程列表*/

    /* stack point and entry 栈对应的指针*/
    void       *sp;                                     /**< stack point 栈指针*/
    void       *entry;                                  /**< entry 入口函数*/
    void       *parameter;                              /**< parameter 参数*/
    void       *stack_addr;                             /**< stack address 栈的地址*/
    rt_uint32_t stack_size;                             /**< stack size 栈的大小*/

    /* error code */
    rt_err_t    error;                                  /**< error code 线程错误代码*/

    rt_uint8_t  stat;                                   /**< thread status 线程状态*/
//对称多处理器, M3只有一个内核, 不会用到
#ifdef RT_USING_SMP
    rt_uint8_t  bind_cpu;                               /**< thread is bind to cpu */
    rt_uint8_t  oncpu;                                  /**< process on cpu` */

    rt_uint16_t scheduler_lock_nest;                    /**< scheduler lock count */
    rt_uint16_t cpus_lock_nest;                         /**< cpus lock count */
    rt_uint16_t critical_lock_nest;                     /**< critical lock count */
#endif /*RT_USING_SMP*/

    /* priority */
    rt_uint8_t  current_priority;                    /**< current priority 当前的优先级*/
    rt_uint8_t  init_priority;                       /**< initialized priority 初始化时候的优先级(在优先级继承的时候使用)*/
#if RT_THREAD_PRIORITY_MAX > 32
    rt_uint8_t  number;
    rt_uint8_t  high_mask;
#endif
    rt_uint32_t number_mask;

#if defined(RT_USING_EVENT)
    /* thread event */
    rt_uint32_t event_set;
    rt_uint8_t  event_info;
#endif

#if defined(RT_USING_SIGNALS)
    rt_sigset_t     sig_pending;                        /**< the pending signals */
    rt_sigset_t     sig_mask;                           /**< the mask bits of signal */

#ifndef RT_USING_SMP
    void            *sig_ret;                           /**< the return stack pointer from signal */
#endif
    rt_sighandler_t *sig_vectors;                       /**< vectors of signal handler */
    void            *si_list;                           /**< the signal infor list */
#endif

    rt_ubase_t  init_tick;                              /**< thread's initialized tick 线程初始化计数值*/
    rt_ubase_t  remaining_tick;                         /**< remaining tick 当前剩余的计数值*/

    struct rt_timer thread_timer;                       /**< built-in thread timer 一个内置的定时器*/

    void (*cleanup)(struct rt_thread *tid);             /**< cleanup function when thread exit 退出回调函数*/

    /* light weight process if present */
#ifdef RT_USING_LWP
    void        *lwp;
#endif

    rt_uint32_t user_data;                             /**< private user data beyond this thread */
};
typedef struct rt_thread *rt_thread_t;

cleanup函数指针指向的函数,会在线程退出的时候,被idle线程回调一次,执行用户设置的清理现场等工作。

成员user_data可由用户挂接一些数据信息到线程控制块中,以提供类似线程私有数据的实现

线程属性

线程状态

image-20240127164313400

优先级

最大支持 256 个线程优先级 (0~255),数值越小的优先级越高,0 为最高优先级。在一些资源比较紧张的系统中,可以根据实际情况选择只支持 8 个或 32 个优先级的系统配置

对于 ARM Cortex-M系列,普遍采用 32 个优先级。最低优先级默认分配给空闲线程使用,用户一般不使用。

时间片

每个线程都有时间片这个参数,但时间片仅对优先级相同的就绪态线程有效。

**注意: **线程里面不要有死循环, 否则低优先级任务不会吧执行到

错误码

/* RT-Thread error code definitions */
#define RT_EOK                          0               /**< There is no error */
#define RT_ERROR                        1               /**< 普通错误 */
#define RT_ETIMEOUT                     2               /**< Timed out */
#define RT_EFULL                        3               /**< 资源已满 */
#define RT_EEMPTY                       4               /**< 无资源 */
#define RT_ENOMEM                       5               /**< No memory */
#define RT_ENOSYS                       6               /**< No system */
#define RT_EBUSY                        7               /**< Busy */
#define RT_EIO                          8               /**< IO error */
#define RT_EINTR                        9               /**< Interrupted system call */
#define RT_EINVAL                       10              /**< 非法参数 */

状态切换

image-20240127165225864

image-20240127165707366

image-20240127165835227

系统线程

在RT-Thread内核中的系统线程有空闲线程和主线程。

空闲线程

系统创建的最低优先级的线程,线程状态永远为就绪态。当系统中无其他就绪线程存在时,调度器将调度到空闲线程,它通常是一个死循环,且永远不能被挂起。

空闲线程在RT-Thread也有着它的特殊用途:

线程运行完毕,系统将自动删除线程:自动执行rt_thread_exit()函数,先将该线程从系统就绪队列中删除,再将该线程的状态更改为关闭状态,不再参与系统调度,然后挂入rt_thread_defunct僵尸队列(资源未回收、处于关闭状态的线程队列)中,最后空闲线程会回收被删除线程的资源。

也提供了接口来运行用户设置的钩子函数,在空闲线程运行时会调用该钩子函数,适合钩入功耗管理、看门狗喂狗等工作。

主线程

入口函数为main_thread_entry()

回在这个线程里面初始化软件, 然后调用用户的main函数

实际操作API

线程相关的操作包括:创建/初始化、启动、运行、删除/脱离。

动态线程是系统自动从动态内存堆上分配栈空间与线程句柄(初始化 heap 之后才能使用 create 创建动态线程),静态线程是由用户分配栈空间与线程句柄。

image-20240127173904171

create和delete是动态的

init和detach是静态的

创建

/**动态
 * This function will create a thread object and allocate thread object memory
 * and stack.
 *
 * @param name the name of thread, which shall be unique名字
 * @param entry the entry function of thread一个函数指针
 * @param parameter the parameter of thread enter function一个参数
 * @param stack_size the size of thread stack栈的大小
 * @param priority the priority of thread优先级
 * @param tick the time slice if there are same priority thread时间片
 *
 * @return the created thread object
 */
rt_thread_t rt_thread_create(const char *name,
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick)
/**静态
 * This function will initialize a thread, normally it's used to initialize a
 * static thread object.
 *
 * @param thread the static thread object
 * @param name the name of thread, which shall be unique
 * @param entry the entry function of thread
 * @param parameter the parameter of thread enter function
 * @param stack_start the start address of thread stack
 * @param stack_size the size of thread stack
 * @param priority the priority of thread
 * @param tick the time slice if there are same priority thread
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_init(struct rt_thread *thread,
                        const char       *name,
                        void (*entry)(void *parameter),
                        void             *parameter,
                        void             *stack_start,
                        rt_uint32_t       stack_size,
                        rt_uint8_t        priority,
                        rt_uint32_t       tick)

删除

/**动态的时候使用的函数
 * This function will delete a thread. The thread object will be removed from
 * thread queue and deleted from system object management in the idle thread.
 *
 * @param thread the thread to be deleted
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_delete(rt_thread_t thread)
/**静态的时候使用的函数
 * This function will detach a thread. The thread object will be removed from
 * thread queue and detached/deleted from system object management.
 *
 * @param thread the thread to be deleted
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_detach(rt_thread_t thread)

会在运行结束以后自动调用, 不建议使用

启动

/**开始可以被执行
 * This function will start a thread and put it to system ready queue
 *
 * @param thread the thread to be started
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_startup(rt_thread_t thread)

获取当前在运行的任务句柄

/**
 * This function will return self thread object
 *
 * @return the self thread object
 */
rt_thread_t rt_thread_self(void)
{
    return rt_current_thread;
}

可以用于在多个任务执行同一段代码的时候区分

让出处理器

/**
 * This function will let current thread yield processor, and scheduler will
 * choose a highest thread to run. After yield processor, the current thread
 * is still in READY state.
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_yield(void)

在让出CPU以后, 当前的线程依旧是ready状态, 会执行相同优先级的任务

休眠

/**
 * This function will let current thread sleep for some ticks.
 *
 * @param tick the sleep ticks 系统的时钟数
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_sleep(rt_tick_t tick)
/**
 * This function will let current thread delay for some ticks.
 *
 * @param tick the delay ticks
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_delay(rt_tick_t tick)
{
    return rt_thread_sleep(tick);
}
/**
 * This function will let current thread delay for some milliseconds.
 *
 * @param ms the delay ms time使用毫秒级别延时
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_mdelay(rt_int32_t ms)

控制

/**
 * This function will control thread behaviors according to control command.
 *
 * @param thread the specified thread to be controlled
 * @param cmd the control command, which includes
 *  RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;控制优先级
 *  RT_THREAD_CTRL_STARTUP for starting a thread;启动一个线程
 *  RT_THREAD_CTRL_CLOSE for delete a thread;删除一个线程
 *  RT_THREAD_CTRL_BIND_CPU for bind the thread to a CPU.把一个线程绑定在某一个CPU
 * @param arg the argument of control command
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)

设置以及删除idle线程的hook函数

/**
 * @ingroup Hook
 * This function sets a hook function to idle thread loop. When the system performs
 * idle loop, this hook function should be invoked.
 *
 * @param hook the specified hook function
 *
 * @return RT_EOK: set OK
 *         -RT_EFULL: hook list is full
 *
 * @note the hook function must be simple and never be blocked or suspend.
 */
rt_err_t rt_thread_idle_sethook(void (*hook)(void))
/**
 * delete the idle hook on hook list
 *
 * @param hook the specified hook function
 *
 * @return RT_EOK: delete OK
 *         -RT_ENOSYS: hook was not found
 */
rt_err_t rt_thread_idle_delhook(void (*hook)(void))

空闲线程是一个线程状态永远为就绪态的线程,因此设置的钩子函数必须保证空闲线程在任何时刻都不会处于挂起状态,例如 rt_thread_delay(),rt_sem_take() 等可能会导致线程挂起的函数都不能使用。

设置调度器hook函数

用户可能会想知道在一个时刻发生了什么样的线程切换,可以通过调用下面的函数接口设置一个相应的钩子函数。

/**
 * This function will set a hook function, which will be invoked when thread
 * switch happens.
 *
 * @param hook the hook function, 可以获取线程来的位置以及下一个线程
 */
void rt_scheduler_sethook(void (*hook)(struct rt_thread *from, struct rt_thread *to))

实际使用

void test_thread(void * parameter){
    int16_t i=0;
    while(1)
    {
        rt_kprintf("test threader\n");
        rt_thread_mdelay(1000);
        if(i++>10)
            break;
    }
}

int main(void)
{
    test_prt = rt_thread_create("test", test_thread, RT_NULL, 300, 20, 20);
    if(test_prt != RT_NULL)
    {
        LOG_D("malloc test thread successed\n");
    }else{
        LOG_E("malloc test thread fail\n");
    }
    rt_thread_startup(test_prt);

}

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

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

相关文章

利用OpenCV实现物流与生产线自动化的革命性突破

背景介绍&#xff1a; 在当今高度自动化的时代&#xff0c;物流和生产线上的每一个环节都关乎企业的核心竞争力。传统的生产方式往往依赖于人工检测和操作&#xff0c;这不仅效率低下&#xff0c;而且容易出错。为了解决这一问题&#xff0c;越来越多的企业开始寻求利用计算机视…

流畅的Python(七)-函数装饰器和闭包

一、核心要义 主要解释函数装饰器的工作原理&#xff0c;包括最简单的注册装饰器和较复杂的参数化装饰器。同时&#xff0c;因为装饰器的实现依赖于闭包&#xff0c;因此会首先介绍闭包存在的原因和工作原理。 二、代码示例 1、变量作用域规则 #!/usr/bin/env python # -*-…

记录一次使用ant design 中 ConfigProvider来修改样式导致样式改变的问题(Tabs嵌套Tabs)

一 说明 继之前的一篇文章&#xff1a;antd5 Tabs 标签头的文本颜色和背景颜色修改 后&#xff0c;发现在被修改后的Tab中继续嵌套Tabs组件&#xff0c;这个新的Tabs组件样式跟外层Tabs样式也是一致的&#xff0c;如下图所示&#xff1a; 二 原因 在修改外层tabs样式时&…

学习Spring的第十三天

非自定义bean注解开发 设置非自定义bean : 用bean去修饰一个方法 , 最后去返回 , spring就把返回的这个对象,放到Spring容器 一 :名字 : 如果bean配置了参数 , 名字就是参数名 , 如果没有 , 就是方法名字 二 : 如果方法产生对象时 , 需要注入数据 , 在方法参数设置即可 , …

iOS 包含行间距计算富文本size

在一次开发过程中&#xff0c;发现带有行间距的富文本计算高度&#xff0c;会有不准确的情况&#xff0c;富文本内容明明很长&#xff0c;但是计算出的高度只有不到20像素&#xff0c;导致整个cell的高度计算异常。 需求上是文字固定宽度&#xff0c;最多显示3行&#xff0c;超…

【Simulink系列】——动态系统仿真 之 简单系统

引入 不同的系统具有不同的输入与输出。一般来说&#xff0c;输入输出数目越多&#xff0c;系统越复杂。最简单的系统只要一个输入一个输出&#xff08;SISO&#xff09;&#xff0c;且其任意时刻的输出只与当前时刻的输入有关。 一、简单系统定义 对于满足下列条件的系统&a…

android 网络拦截器统一处理请求参数和返回值加解密实现

前言 项目中遇到参数加密和返回结果加密的业务 这里写一下实现 一来加深记忆 二来为以后参考铺垫 需求 项目在开发中涉及到 登陆 发验证码 认证 等前期准备接口 这些接口需要单独处理 比如不加密 或者有其他的业务需求 剩下的是登陆成功以后的业务需求接口 针对入参和返回值…

【Android新版本兼容】onBackPressed()方法被弃用的解决方案

提示&#xff1a;此文章仅作为本人记录日常学习使用&#xff0c;若有存在错误或者不严谨得地方欢迎指正。 文章目录 一、使用 AndroidX API 实现预测性返回手势1.1 添加依赖1.2 启用返回手势1.3 注册OnBackPressedCallback()方法来处理返回手势 一、使用 AndroidX API 实现预测…

【MIT 6.S081】2020, 实验记录(5),Lab: lazy allocation

目录 Task 1: Eliminate allocation from sbrk()Task 2: Lazy allocationTask 3: Lazytests and Usertests 在学习了 page fault 这一节课后&#xff0c;了解了操作系统是如何结合 page table 和 trap 利用 page fault 来实现一系列的神奇的功能。这个 lab 就是在 XV6 中实现 l…

前端面试拼图-数据结构与算法

摘要&#xff1a;总结一些前端算法题&#xff0c;持续更新&#xff01; 一、数据结构与算法 时间复杂度-程序执行时需要的计算量&#xff08;CPU&#xff09; 空间复杂度-程序执行时需要的内存空间 前端开发&#xff1a;重时间&#xff0c;轻空间 1.把一个数组旋转k步 arr…

CSS的复合选择器

一,什么是复合选择器 常用的复合选择器有:后代选择器、子选择器、并集选择器和伪类选择器。 二,后代选择器(用空格)(重点) 后代选择器也称包含选择器,可以选择父元素里面的子元素。写法就是外层标签在前面,内层标签写后面,中间要有空格隔开。当标签发生嵌套时,内层…

PostgreSQL 也很强大,为何在中国大陆,MySQL 成为主流,PostgreSQL 屈居二线呢?

问题&#xff1a; PostgreSQL 也很强大&#xff0c;为何在中国大陆&#xff0c;MySQL 成为主流&#xff0c;PostgreSQL 屈居二线呢&#xff1f;PostgreSQL 能否替代 MySQL&#xff1f; 当我们讨论为何 MySQL 在中国大陆成为主流而 PostgreSQL 屈居二线时&#xff0c; 我们其实…

servlet会话API

servlet会话API 您可以使用servlet会话API中定义的类和接口来创建和管理用户会话。servlet会话API提供的用于创建和管理用户会话的各种接口有javax.servlet.http.HttpSession、javax.servlet.httpSessionListener和javax.servlet.http.HttpSessionBindingListener和javax.serv…

unity角色触摸转向

1、挂载脚本到角色的父物体A上 2 、以屏幕左边的触摸为移动&#xff0c;右边为转向操作 3、加载角色时&#xff0c;将角色的父物体设置为A&#xff0c;须将角色的位置和角度置0 using System; using System.Collections; using System.Collections.Generic; using UnityEngin…

OTG -- STM32 OTG驱动代码下载及简述(三)

目录 前沿 1 STM32 OTG标准库的获取 2 设备模式代码匹配开发板 2.1 OTG FS全速代码修改 2.2 OTG HS代码修改 2.2.1 OTG HS外部高速PHY运行在高速模式代码修改 2.2.2 OTG HS外部高速PHY运行在全速模式代码修改 2.2.3 OTG HS内部全速PHY运行在全速模式代码修改 前沿 前面…

linux 组建和卸载raid1、raid0详细操作

组raid的最好是相同容量和型号的硬盘&#xff0c;否则会有木桶效应 linux下组raid有很多细节 一、安装raid软件 deb包 apt-get install mdadm或dnf包 dnf install mdadm二、组raid1-镜像&#xff0c;组raid0-并列 raid1和raid0只有在madam命令时一点点不同&#xff0c;其他…

python 下载腾讯在线文档

import requests""" 1. 手动到chrome获取下载请求 2. 获取excel的动态id 3. 拼出excel的下载链接 4. 下载 """class Excel:def __init__(self):self.cookie_string ""self.headers {"authority": "docs.qq.com"…

中缀转后缀

概念 什么是后缀表达式&#xff1f; 后缀表达式&#xff0c;其实就是一个中缀表达式 AOB > ABO &#xff08;A、B是式子、O 为运算符&#xff09;&#xff0c;将运算符向后放 中转后举例 中缀表达式&#xff1a;&#xff08;a b&#xff09;* c - (d / c) 首先&#xff…

CANoe学习笔记—关于cfg工程界面的分类

创建一个工程过程中&#xff0c;如何规划好界面设置&#xff0c;对于后续使用和维护起到了非常好的作用。故整理下 1&#xff1a;首先规划好大致结构图 CANoe中工程的规划Trace界面ConfigurationBuildInToolControlDiagnosticPanel预留 当然&#xff1a;此格式不是固定的&…

高级FPGA开发之基础协议PCIe

基础协议之PCIe部分 一、TLP包的包头 在PCIe的系统中&#xff0c;tlp包的包头的结构有许多部分是相似的&#xff0c;通过掌握这些常规的包头&#xff0c;能帮助理解在PCIe总线上各个设备之间如何进行数据的收发。 通用的字段 通用字段作用Fmt决定了包头是3DW还是3DW&#xff…