RT-Thread动态和静态创建线程

2023-10-29

上一篇:RT-Thread线程管理教程   http://t.csdn.cn/phnwQ

目录

一、静态创建线程和动态创建线程的区别

二、创建线程的常用函数

三、动态创建线程

四、静态创建线程:

五、动态和静态创建线程结合+线程调度hook函数使用


一、静态创建线程和动态创建线程的区别

        RT-Thread是一个开源的嵌入式实时操作系统,支持静态创建线程和动态创建线程两种方式。

        静态创建线程是在编译时就确定了线程的数量和属性,将线程的控制块和堆栈空间预分配好,然后在系统初始化时创建。静态创建线程的优点是创建速度快,不会产生动态内存分配的开销,适用于线程数量确定且固定的应用场景。

        动态创建线程是在运行时根据需要动态地创建线程,可以根据不同的应用场景动态地调整线程的数量和属性。动态创建线程的优点是灵活性高,可以根据系统负载情况动态地创建或销毁线程,适用于线程数量不确定或者需要动态调整的应用场景。

        总的来说,静态创建线程适用于线程数量确定且固定的应用场景,动态创建线程适用于线程数量不确定或者需要动态调整的应用场景。具体选择哪种方式,需要根据具体的应用场景和系统需求来进行权衡和选择。

二、创建线程的常用函数

线程创建函数,返回一个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)                  //线程调度的时间片大小

线程删除函数,传入创建函数的返回类型:

rt_thread_delete(rt_thread_t thread)    

线程的初始化函数:

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)            //线程调度的时间片大小

脱离线程函数:

rt_thread_detach(rt_thread_t thread)

线程启动函数:

rt_thread_startup(rt_thread_t thread)

获得当前线程:

rt_thread_self(void)

线程睡眠函数:

rt_err_t rt_thread_sleep(rt_tick_t tick)
rt_err_t rt_thread_delay(rt_tick_t tick)    //tick决定睡眠时间

rt_thread_mdelay(rt_int32_t ms)

设置idle线程hook函数:

rt_thread_idle_sethook(void (*hook)(void))

删除idle线程hook函数:

rt_thread_idle_delhook(void (*hook)(void))

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

设置线程调度器hook函数:

 rt_scheduler_sethook(void (*hook)(struct rt_thread *from, struct rt_thread *to))

三、动态创建线程

        在RT-Thread中,动态创建的线程是由内核堆分配的内存来存储线程的控制块和栈空间。当动态创建的线程完成其任务并被终止时,RT-Thread会释放该线程使用的内存空间。这是由RT-Thread内核的垃圾回收机制来完成的,它会将已经终止的线程的控制块和栈空间归还给内核堆。因此,当您使用RT-Thread动态创建线程时,无需担心内存释放的问题,RT-Thread内核会自动处理它。所以在动态创建线程的时候,线程删除函数可用可不用。

        下面是动态创建一个led线程的代码,运行下面程序,系统将会创建一个led的线程,出现led闪烁的现象:

#include <rtthread.h>
#include "board.h"

rt_thread_t led1_th_ptr = NULL;

void LED1_th_entry(void *parameter)      //LED1线程
{
    uint8_t led1 = rt_pin_get("PF.9");   //获取led引脚号
    rt_pin_mode(led1, PIN_MODE_OUTPUT);  //设置io口模式
    rt_kprintf("led1_th_ptr is running...\n");

    rt_pin_write(led1, PIN_LOW);         //IO给低电平
    rt_thread_mdelay(500);
    rt_pin_write(led1, PIN_HIGH);
    rt_thread_mdelay(500);
}

int main(void)
{

    while (1)
    {

        led1_th_ptr = rt_thread_create("led1_th",LED1_th_entry,NULL,1024,20,5);    //动态创建LED1线程

        if(led1_th_ptr == RT_NULL)
        {
            rt_kprintf("led1_th_ptr create error...\n");
            return RT_ERROR;                                    //创建失败返回错误码
        }
        else
        {
            rt_kprintf("led1_th_ptr create successed ...\n");    //创建成功后打印成功信息
            if(rt_thread_startup(led1_th_ptr) == RT_EOK)         //启动LED1线程
            {
                rt_kprintf("led1_th_ptr startup successed ...\n");//启动成功打印成功信息
            }
            else {
                rt_kprintf("led1_th_ptr startup error ...\n");    //启动失败打印错误信息
                return RT_ERROR;                                  //返回一个错误码
            }
        }

        rt_thread_mdelay(1000);
        rt_kprintf("\n");
    }

}

四、静态创建线程:

        关于静态创建线程,RT-Thread 并不会自动释放线程所使用的内存。在静态创建线程时,需要手动分配内存资源,并传递给 rt_thread_init 函数。由于内存是静态分配的,RT-Thread 不会自动释放它。如果你想要释放线程所使用的内存,需要在线程结束时手动处理。但是,对于静态创建的线程,通常不需要释放内存,因为它们的生命周期通常与整个应用程序相同。在静态创建的线程运行完后,我们需要用线程脱离函数rt_thread_detach()将线程脱离,这样才能重新静态创建线程。

        下面是静态创建一个led的线程代码:

#include <rtthread.h>
#include "board.h"

struct rt_thread led2_th_ptr;

void LED2_th_entry(void *parameter)      //LED2线程
{
    uint8_t led2 = rt_pin_get("PF.10");   //获取led引脚号
    rt_pin_mode(led2, PIN_MODE_OUTPUT);  //设置io口模式
    rt_kprintf("led2_th_ptr is running...\n");

    rt_pin_write(led2, PIN_HIGH);         //IO给低电平
    rt_thread_mdelay(500);
    rt_pin_write(led2, PIN_LOW);
    rt_thread_mdelay(500);
}

int main(void)
{
    rt_uint8_t rt = 0;
    rt_uint8_t th2_stack[1024]={0};
    while (1)
    {
        rt = rt_thread_init(&led2_th_ptr, "led2_th", LED2_th_entry, NULL,         
                              th2_stack,sizeof(th2_stack), 19, 5);  //静态创建LED2线程

        if(rt < 0)
        {
            rt_kprintf("led2_th_ptr create error...\n");
            return rt;
        }
        else {
            rt_kprintf("led2_th_ptr create successed ...\n");
            if(rt_thread_startup(&led2_th_ptr) == RT_EOK)         //启动LED2线程
            {
                rt_kprintf("led2_th_ptr startup successed ...\n");
            }
        }
        rt_thread_mdelay(1000);
        rt_thread_detach(&led2_th_ptr);     //静态LED2线程脱离
        rt_kprintf("\n");
    }

}

五、动态和静态创建线程结合+线程调度hook函数使用

        在整个系统的运行时,系统都处于线程运行、中断触发 - 响应中断、切换到其他线程,甚至是线程间的切换过程中,或者说系统的上下文切换是系统中最普遍的事件。有时用户可能会想知道在一个时刻发生了什么样的线程切换,可以通过调用线程调度hook函数rt_scheduler_sethook()接口设置一个相应的钩子函数。在系统线程切换时,这个钩子函数将被调用。

        下面是动态创建led1线程和静态创建led2线程并使用线程调度hook函数查看线程调度情况的代码,运行这段代码,开发板上两个led灯交替闪烁,并且在串口中打印线程调度的关系:

#include <rtthread.h>
#include "board.h"

rt_thread_t led1_th_ptr = NULL;
struct rt_thread led2_th_ptr;

void LED1_th_entry(void *parameter)      //LED1线程
{
    uint8_t led1 = rt_pin_get("PF.9");   //获取led引脚号
    rt_pin_mode(led1, PIN_MODE_OUTPUT);  //设置io口模式
    rt_kprintf("led1_th_ptr is running...\n");

    rt_pin_write(led1, PIN_LOW);         //IO给低电平
    rt_thread_mdelay(500);
    rt_pin_write(led1, PIN_HIGH);
    rt_thread_mdelay(500);
}

void LED2_th_entry(void *parameter)      //LED2线程
{
    uint8_t led2 = rt_pin_get("PF.10");   //获取led引脚号
    rt_pin_mode(led2, PIN_MODE_OUTPUT);  //设置io口模式
    rt_kprintf("led2_th_ptr is running...\n");

    rt_pin_write(led2, PIN_HIGH);         //IO给低电平
    rt_thread_mdelay(500);
    rt_pin_write(led2, PIN_LOW);
    rt_thread_mdelay(500);
}

void scheduler_hook(struct rt_thread *from, struct rt_thread *to)   //钩子函数
{
    rt_kprintf("from:%s ---> to:%s\n",from->name,to->name);         //打印线程切换关系
}

int main(void)
{
    rt_uint8_t rt = 0;
    rt_uint8_t th2_stack[1024]={0};
    rt_scheduler_sethook(scheduler_hook);       //设置调度器钩子函数
    while (1)
    {

        rt = rt_thread_init(&led2_th_ptr, "led2_th", LED2_th_entry, NULL, th2_stack,sizeof(th2_stack), 19, 5);  //静态创建LED2线程
        led1_th_ptr = rt_thread_create("led1_th",LED1_th_entry,NULL,1024,20,5);    //动态创建LED1线程

        if(led1_th_ptr == RT_NULL)
        {
            rt_kprintf("led1_th_ptr create error...\n");
            return RT_ERROR;
        }
        else
        {
            rt_kprintf("led1_th_ptr create successed ...\n");
            if(rt_thread_startup(led1_th_ptr) == RT_EOK)         //启动LED1线程
            {
                rt_kprintf("led1_th_ptr startup successed ...\n");
            }
            else {
                rt_kprintf("led1_th_ptr startup error ...\n");
                return RT_ERROR;
            }
        }
        if(rt < 0)
        {
            rt_kprintf("led2_th_ptr create error...\n");
            return rt;
        }
        else {
            rt_kprintf("led2_th_ptr create successed ...\n");
            if(rt_thread_startup(&led2_th_ptr) == RT_EOK)         //启动LED2线程
            {
                rt_kprintf("led2_th_ptr startup successed ...\n");
            }
        }
        rt_thread_mdelay(1000);
        rt_thread_detach(&led2_th_ptr);     //静态LED2线程脱离
        rt_kprintf("\n");
    }

}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RT-Thread动态和静态创建线程 的相关文章

  • Modbus RTU协议认识

    Modbus RTU协议认识 一 通信模式 Modbus RTU协议是一个主从协议 主机发出请求 从机返回响应 从机不能主动发送数据 同一时刻总线上只能有一个主机 但可以有多个从机 从机之间不能相互通信 二 通信角色 主机 主机没有编号 因
  • MYSQL修改时区

    按照公司要求 java程序和数据库时区保持在UTC时区 本文将针对自建数据库 提供修改时区方法 含盖windows和ubuntu环境 一 Windows环境 1 找到mysql配置文件 my ini mysql由于按照方式不同 存在位置可能

随机推荐

  • Python基础知识: for . in range()循环

    Python for x in range 循环打印四个数字能生成多少个互不相同且无重复数字的三位数 记录打印三位数的个数 count 0 用i控制第一位输出的位数 for i in range 1 5 用j控制第二位输出的位数 for j
  • (转)大厂的产品经理是怎样进行产品迭代的?

    先说一下背景 大厂和小厂都呆过 呆过野蛮生长的传统集团的互联网部门 呆过上市的中型二线互联网公司 呆过APPLE STORE行业APP排名第一的产品公司 现在呆在全球一万多员工的超级独角兽公司 其实各个产品公司的迭代流程都大同小异 因为规范
  • Flink 1.11.2 在K8s里基于NFS搭建高可用集群

    使用官方的docker镜像搭建job ha集群一直失败 最后参考了flink1 11 2 的start cluster sh 脚本 对docker 的启动脚本进行了调整 终于成功了 希望能够帮助到大家 需要注意的是 我的k8s环境是基于k8
  • GIS开发一:OpenLayers在线瓦片数据源汇总

    文章目录 1 概述 2 地图数据源 2 1 Google 2 2 OpenStreetMap 2 3 Thunderforest 2 4 Mapbox 2 5 ArcGIS 2 6 Bing地图 2 7 高德地图 2 8 百度地图 2 9
  • 自用入门人工智能笔记

    定义 百度百科的定义 机器学习的主要研究对象是人工智能 特别是如何在经验学习中改善具体算法的性能 能通过经验自动改进的计算机算法的研究 用数据和以往的经验来优化计算基础性的性能标准 Machine Learning书中的定义 如果一个程序可
  • Unity AssetBundle(2):工具UnityStudio

    一 UnityStudio 作用有两个 查看AssetBundle内资源 File gt LoadFile 提取AssetBundle内资源 Export 下载地址 UnityStudio releases地址 Perfare UnityS
  • Linux下Mysql 5.6.21 tar包安装实践

    好久没玩linux 由于项目需要部署新的linux开发环境 包括安装jdk tomcat redis mysql 趁着有时间 赶紧部署好 jdk tomcat redis很快就部署好了 唯独mysql让我折腾了一阵 先安装了我之前就安装过的
  • 数据库性能优化必读,AntDB-M数据库的哈希索引设计

    数据库加快访问速度的关键技术之一就是索引 索引的设计及使用方式极大程度上影响了数据库的性能 AntDB M支持Hash BTree两种索引类型 本文主要讲解Hash索引的相关设计 并给出一些使用建议 1 相关概念 桶 用于定位索引记录的容器
  • 如何在本地操作Redis

    1 下载redis到本地 下载Redis x64 xxx zip压缩包并解压 我这里解压到了D Redis Redis下载地址 2 开启并连接Redis 1 进入解压的文件夹中 按住shift 右击鼠标 点击在此处打开命令窗口 运行命令 r
  • MySQL安装时常见问题和解决方案【详解】

    目录 1 更改不了后缀名 2 配置文件设置错误 3 使用 mysqld install命令安装MySQL服务失败 4 使用 mysqld initialize console命令初始化MySQL 失败 5 使用net start mysql
  • java 中 BigDecimal 详解

    首先 学习一个东西 我们都必须要带着问题去学 这边我分为 为什么 是什么 怎么用 为什么要用BigDecimal 首先 我们先看一下 下面这个现象 那为什么会出现这种情况呢 因为不论是float 还是double都是浮点数 而计算机是二进制
  • 时间的几个实用函数 FILETIME UnixTime的转换

    filetimeToUnixTime windos filetime 起于 1601 01 01T00 00 00Z 单位 100 纳秒 UnixTime 起于 1970 01 01T00 00 00Z 单位 秒 它们的起始时间差了 116
  • Java实现第九届蓝桥杯测试次数

    测试次数 题目描述 x星球的居民脾气不太好 但好在他们生气的时候唯一的异常举动是 摔手机 各大厂商也就纷纷推出各种耐摔型手机 x星球的质监局规定了手机必须经过耐摔测试 并且评定出一个耐摔指数来 之后才允许上市流通 x星球有很多高耸入云的高塔
  • [踩坑记] CUDA环境下bitsandbytes安装报错/异常解决

    关键词 模型量化 bitsandbytes bitsandbytes报错 大模型环境 CUDA环境 1 问题描述 在部署大模型LLaMA的过程中 需要安装量化工具包bitsandbytes 环境如下 操作系统 Ubuntu 18 04 GP
  • 基于ChatGPT3.5 API实现的私有化web程序源码+使用说明,一键部署属于自己定制化的 chatgpt web 程序

    chatgpt web 本项目可以一键部署属于自己定制化的 chatgpt web 程序 兼容gpt3 5 只需下载release中对应平台的项目文件 修改配置后执行 打开 http 127 0 0 1 8080 便可以获得属于自己的cha
  • KEIL5 只有下载程序后不运行,只有在调试模式下多次点击全速运行代码才能跑起来的解决办法

    最近 使用KEIL5下载调试时遇到了一个很奇怪的现象 下载程序后哪怕是断电重启设备 程序都无法运行 在Flash Dowmload 下已经设置了Reset and Run 只有在Debug模式下 且多次点击全速运行 才能够把程序跑起来 最后
  • keyshot场景素材导入_KeyShot导入Rhino室内场景渲染的详细方法

    在KeyShot怎样导入Rhino室内场景渲染呢 下面就为大家分享KeyShot导入Rhino室内场景渲染的图文教程 有需要的可以来了解了解哦 KeyShot导入Rhino室内场景渲染的详细方法 1 打开一个rhino场景 这是一个简单的室
  • powershell 脚本启动优化

    需求分析 powershell 启动慢的主要原因是 profile中的终端配置加载时间长 当我们打开powershell终端进行交互时 加载时间长 尚可忍受 但当我们的脚本 执行powershell脚本时 较长的加载时间 是不可接受的 优化
  • 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java动物爱心救助平台s9dza

    如果你自己基础不好或者是小白的情况下那就建议你选择网站 系统类的去做 但是还得问问你们导师 如果你们导师没问题就可以 因为有的导师是不愿意你们选择做网站 系统的 毕竟做的人比较多 重复率调高 选择这种题目都是要创新功能 所以会比较棘手 以下
  • RT-Thread动态和静态创建线程

    上一篇 RT Thread线程管理教程 http t csdn cn phnwQ 目录 一 静态创建线程和动态创建线程的区别 二 创建线程的常用函数 三 动态创建线程 四 静态创建线程 五 动态和静态创建线程结合 线程调度hook函数使用