【STM32RT-Thread零基础入门】 4. 线程介绍(理论)

news2025/1/17 3:16:06

文章目录

  • 前言
  • 一、线程的概念
  • 二、线程的调度
  • 三、上下文切换
  • 四、线程的重要属性
    • 1. 线程栈
    • 2. 线程的状态
    • 3. 线程优先级
    • 4. 线程时间片
    • 5. 线程的入口函数
  • 五、RT-Thread命令查看系统线程信息
  • 总结


前言

前文中的最后一个任务发现,一个main()函数很难同时实现按键功能和闪灯功能,就好像人很难同时完成左手画圆右手画方一样,这种情况可以安排一人去画圆、一人去画方,并行进行就很容易了,两人各司其职,互不干扰。
操作系统中,一个线程就像做事的一个人。一个操作系统可以有多个线程,不同的线程完成不同的小任务,各司其职完成整个系统大任务。


一、线程的概念

日常生活中,完成一个复杂的任务,一般会先将他分解成多个简单、容易解决的小任务,再将小任务分配给不同的人完成,当小任务逐个被完成时,复杂任务也就随之完成了。

嵌入式系统一般也是用于完成一些特定任务而设计的,这些特定任务可能比较复杂,这就要求开发人员把复杂的任务进行功能分解,形成若干个不同功能的小任务,而不同功能的小任务由运行于操作系统中的不同程序来完成,再由操作系统统一协调各个程序之间的运行。这些运行在操作系统之上的程序单元就是线程。

当合理地划分任务并正确地执行时,这种设计能够让系统满足实时系统的性能及时间的要求,例如让嵌入式系统执行这样的任务,系统通过红外传感器采集寻迹数据,并根据数据采集结果决定小车的行驶方向(如直走,纠偏等),在多线程实时系统中,可以将这个任务分解成两个子任务,如下图所示:
在这里插入图片描述
子任务1不间断地读取传感器数据,并将数据写到共享内存中。
子任务2周期性地从共享内存中读取数据,并根据传感器数据修正行进路线。

在 RT-Thread 中,线程是实现任务的载体,它是 RT-Thread 中最基本的调度单位。


二、线程的调度

调度是什么?先讲个故事,小朋友去游乐场玩荡秋千,秋千只有一个,但想玩的小朋友很多,那怎么办?游乐场的服务员小姐姐就想了一个办法:想玩的小朋友要排队,一个一个轮流玩,而且每人一次只能玩5分钟,如果还想再玩一次的话,得重新排队。这样,听话的小朋友们就在服务员小姐姐的统一调度下开心有序的玩起了荡秋千。

对于单核系统,CPU就好比秋千,线程就好比游乐场的小朋友,系统中有多个线程,每个线程的运行都要占有CPU,而CPU只有一个,这样,想让所有线程在操作系统上有序地运行,就需要有一个统一的协调者,这个协调者我们叫它调度器,而它的工作就是负责线程调度,给不同的线程分配运行时间,使操作系统上的所有线程有序地运行。综上所述,线程调度是指按照特定机制为多个线程分配CPU的使用权。

线程调度方式常见的有两种,分别为分时调度抢占式调度
(1)分时调度就是所有线程轮流拥有CPU的使用权,平均分配每个线程占用CPU的时间;
(2)抢占式调度就是让优先级高的线程优先使用CPU,如果线程的优先级相同,则会像分时调度一样轮流使用CPU。

RT-Thread实时操作系统,采用的调度方式是抢占式调度方式。

三、上下文切换

线程是程序的一个运行实例,线程执行时的运行环境称为上下文,每个线程都有自己的上下文,包括程序的代码、数据、堆栈、寄存器、程序计数器等。

操作系统的调度器在进行线程调度时,会发生上下文件切换,从正在运行的线程的上下文,切换到另一个线程的上下文。相当从一个程序代码,切换到另一个程序代码,但又不仅是代码的切换,上下文件的其它内容,如数据、堆栈、寄存器、程序计数器等也要一起切换。

线程的运行,是需要运行环境的,对于线程来说,运行环境就是CPU资源,包括运算单元、程序指针、堆栈指针以及各种通用寄存器。当线程运行时,它会认为自己是以独占CPU资源的方式在运行,会根据自己需要对这些资源进行修改。

而CPU资源只有一套,当另一个线程运行时,它也想独占CPU资源,那么前面已占用CPU资源的线程必须把CPU资源让给后面的线程使用。但它又担心后面的线程把CPU资源修改了,所以它在让出资源之前,还要做一件重要的事,就是把它当前的资源使用情况记录下来(这个动作也叫保护现场),方便下次运行时重新布置资源。

另一个线程得到资源后,此时得到的资源的状态不适合它运行,因此在运行之前,它必须根据自己的需要把资源重新布置(这个动作也叫恢复现场)才能运行

这种把CPU资源从一个状态切换到另一个状态的过程,就是上下文切换。

我们拿舞台剧来做个不太恰当的比喻。每一场舞台剧的表演都需要一个舞台资源(场地、灯光和道具等),而且独占舞台资源,表演时会根据自己表演剧情的需要,把舞台资源进行布置。而到下一场表演时,也要独占舞台资源,而且此时的舞台资源布置情况不适合下一场表演的剧情需要,必须在开始前重新布置舞台资源。所在,从一场表演切换到另一场表演时,需要进行舞台场景的切换。


四、线程的重要属性

1. 线程栈

线程栈:用于保存线程的上下文,函数调用过程、局部变量等

进行上下文切换时,需要记录线程的上下文信息,那么就需要有一个地方来保存这些数据。RT-Thread的每一各线程都具有独立的栈,当进行线程切换时,会将当前线程的上下文保存在栈中,当线程要恢复运行时,再从栈中读取上下文信息,进行恢复。

线程栈还用来存放函数中的局部变量,函数中的局部变量从线程空间中申请,在初始时从寄存器中分配(ARM架构),当这个函数再调用另一个函数时,这些局部变量将放入栈中。

线程栈的大小设定:
(1)对于资源相对较大的MCU,可以适当设计较大的线程栈;
(2)在初始时设置较大的栈,例如指定大小为1KB或2KB,然后在FinSH中用list_thread命令查看线程运行过程中线程所使用的栈的大小,通过此命令,能够看到从线程启动运行时,到当前时刻点,线程使用的最大栈深度,而后加上适当的余量形成最终的线程栈大小,最后对栈空间加以修改。

2. 线程的状态

系统运行的过程中,同一时间内只允许一个线程在处理器中运行,从运行的过程上划分,线程有多种不同的运行状态。RT-Thread中,操作系统会自动根据其运行的情况来动态调整它的状态。

状态描述
初始状态当线程刚开始创建还没启动时就处于初始状态;在初始状态下,线程不参与调度。此状态在 RT-Thread 中的宏定义为 RT_THREAD_INIT
就绪状态在就绪状态下,线程按照优先级排队,等待被执行;一旦当前线程运行完毕让出处理器,操作系统会马上寻找最高优先级的就绪态线程运行。此状态在 RT-Thread 中的宏定义为 RT_THREAD_READY
运行状态线程当前正在运行。在单核系统中,只有 rt_thread_self() 函数返回的线程处于运行状态;在多核系统中,可能就不止这一个线程处于运行状态。此状态在 RT-Thread 中的宏定义为 RT_THREAD_RUNNING
挂起状态也称阻塞态。它可能因为资源不可用而挂起等待,或线程主动延时一段时间而挂起。在挂起状态下,线程不参与调度。此状态在 RT-Thread 中的宏定义为 RT_THREAD_SUSPEND
关闭状态当线程运行结束时将处于关闭状态。关闭状态的线程也叫僵尸线程,不参与线程的调度。此状态在 RT-Thread 中的宏定义为 RT_THREAD_CLOSE

RT-Thread提供一系列的操作系统调用接口,使线程的状态在5个状态之间来回切换。几种状态间的切换关系如图所示:
在这里插入图片描述

  • 线程通过调用函数 rt_thread_create/init() 进入到初始状态(RT_THREAD_INIT)
  • 初始状态的线程通过调用函数 rt_thread_startup() 进入到就绪状态(RT_THREAD_READY)
  • 就绪状态的线程被调度器调度后进入运行状态(RT_THREAD_RUNNING)
  • 当处于运行状态的线程调用①中的rt_thread_delay(),rt_sem_take(),rt_mutex_take(),rt_mb_recv()等函数或者获取不到资源时,将进入到挂起状态(RT_THREAD_SUSPEND)
  • 处于挂起状态的线程,如果等待超时依然未能获得资源或由于其他线程释放了资源,那么它将返回到就绪状态;
  • 挂起状态的线程,如果调用rt_thread_delete/detach() 函数,将更改为关闭状态(RT_THREAD_CLOSE)
  • 而运行状态的线程,如果运行结束,就会在线程的最后部分执行 rt_thread_exit() 函数,将状态更改为关闭状态。

3. 线程优先级

RT-Thread 线程的优先级是表示线程被调度的优先程度。每个线程都具有优先级,线程越重要,赋予的优先级就应越高,线程被调度的可能才会越大。

RT-Thread 最大支持 256 个线程优先级 (0~255),数值越小的优先级越高,0 为最高优先级。在一些资源比较紧张的系统中,可以根据实际情况选择只支持 8 个或 32 个优先级的系统配置;对于 ARM Cortex-M 系列,普遍采用 32 个优先级。最低优先级默认分配给空闲线程使用,用户一般不使用。在系统中,当有比当前线程优先级更高的线程就绪时,当前线程将立刻被换出,高优先级线程抢占处理器运行。

4. 线程时间片

回到前文小朋友荡秋千,每个小朋友荡秋千的时间是有限的,不能一直占着秋千,否则会导致其他小朋友不能参与秋千。

同样操作系统中的线程也不能一直占用CPU,每个线程都有时间片这个参数,表示线程每次可以占用CPU运行的时间,当时间片用完,线程就要让出CPU。

但时间片仅对优先级相同的就绪态线程有效。系统对于优先级相同的就绪态线程采用时间片轮转的调度方式进行调度,时间片起到约束线程单次运行时长的作用,其单位是一个系统节拍(OS Tick),后面讲时钟时会讲。

假设有2个优先级相同的就绪态线程A与B,A线程的时间片设置为10,B线程的时间片设置为5,那么当系统中不存在比A优先级高的就绪态线程时,系统会在A、B线程间来回切换执行,并且每次对A线程执行10个节拍的时长,对对 B 线程执行 5 个节拍的时长,如下图,可以看出,线程A占用CPU运行时间较长。所以我们要根据程序所执行的所需长度,定时间片长度,以执行完程序。

在这里插入图片描述

5. 线程的入口函数

线程的入口函数是线程实现预期功能的函数,它是线程第一个运行的函数,也是线程开始运行的地方。线程控制块中的 entry 是线程的入口函数,它是线程实现预期功能的函数。线程的入口函数由用户设计实现,可以有以下几点模式。

(1)无限循环模式

在实时系统中,线程通常是被动式的,这个是由实时系统的特性所决定的,实时系统通常总是等待外界事件的发生,而后进行相应的服务。

void thread_entry(void* paramenter)
{
    while (1)
    {
    /* 等待事件的发生 */
 
    /* 对事件进行服务、进行处理 */
    }
} 

线程看似没有什么限制程序执行的因素,似乎所有的操作都可以执行。但是作为一个实时系统,一个优先级明确的实时系统,如果一个线程中的程序陷入了死循环操作,那么比它优先级低的线程都将不能够得到执行。所以在实时操作系统中必须注意的一点就是:线程中不能陷入死循环操作,必须要有让出 CPU 使用权的动作,如循环中调用延时函数或者主动挂起。用户设计这种无限循环的线程的目的,就是为了让这个线程一直被系统循环调度运行,永不删除。

(2)顺序执行或有限次循环模式:

如简单的顺序语句、do while() 或 for()循环等,此类线程不会循环或不会永久循环,可谓是 “一次性” 线程,一定会被执行完毕。在执行完毕后,线程将被系统自动删除。

static void thread_entry(void* parameter)
{
    /* 处理事务 #1 *//* 处理事务 #2 *//* 处理事务 #3 */
}

五、RT-Thread命令查看系统线程信息

在第3章 PIN设备(GPIO)的使用中的任务4基础上,使用命令查看系统线程信息。在终端输入命令help,观看输出结果,如图所示:
在这里插入图片描述
可以发现help命令可以查看系统支持的所有命令,其中有两个命令与线程相关,分别时ps和list_thread。这两个命令都可以用于查看系统中存在哪些线程,以及线程的信息,其命令输出结果如下图所示:
在这里插入图片描述连个命令输出一样,目前系统有4个线程,分别为tshell、tidle0、timer、main。tshell、tidle0、timer三个线程是系统线程,由系统在启动时自动创建并运行。

  • tshell是用户线程,在系统开启finsh命令组件时创建此线程(默认是开启的),他负责解析并执行终端命令,最后向终端输出命令执行结果;
  • tidle0是一个空闲线程,在系统空闲的时候运行,用于处理系统中一些非紧急的任务,如僵尸线程的资源清理,就是在空闲线程中进行的;
  • timer是定时器线程,负责处理定时器任务;
  • main就是我们程序中的main函数,单独作为一个线程运行,通常也叫主线程。

总结

本章主要讲了线程的基本概念

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

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

相关文章

基于浏览器的插件sider,使用chatgpt3.5生成的连接Redis的代码

一.安装 首先在浏览器安装Sider插件,具体安装步骤https://www.423xz.com/gaoxiao/3949.html 收费情况:每天有几次的免费使用chatgpt3.5的次数,chatgpt4需要付费了。 二.使用步骤: 安装后使用,具体步骤:…

20 张图,透析HTTPs五大知识点

本文详细介绍了 HTTPS 相较于 HTTP 更安全的原因,包括对称加密、非对称加密、完整性摘要、数字证书以及 SSL/TLS 握手等内容,图文并茂、理论与实战结合、建议收藏! 1. 不安全的 HTTP 近些年来,越来越多的网站使用 HTTPS 协议进行…

OpenCV-Python中的图像处理-霍夫变换

OpenCV-Python中的图像处理-霍夫变换 霍夫变换霍夫直线变换霍夫圆环变换 霍夫变换 霍夫(Hough)变换在检测各种形状的技术中非常流行,如果要检测的形状可以用数学表达式描述,就可以是使用霍夫变换检测它。即使要检测的形状存在一点破坏或者扭曲也是可以使…

【产品设计】用设计讲好故事 – JOOX 2020听歌年榜总结

JOOX是腾讯面向东南亚市场战略性的音乐App,作为一个国家化品牌,它面临着一些困难,但同时它通过创意的方式将自己的产品价值观传递给用户。我们在设计产品中,做好一个设计项目,就好比讲一个故事,但这只是一种…

基于php驾校驾驶理论考试模拟系统

驾校驾驶理论考试模拟系统,是基于php编程语言,mysql数据库进行开发,本系统分为用户和管理员两个角色,其中用户可以注册登陆系统,查看考试规则,进行驾照考试,查看考试得分,考试错题&a…

docker安装国产开源数据库tidb 单机版

docker pull pingcap/tidb 创建目录,然后安装tidb mkdir -p /data/tidb/data 创建容器 docker run --name tidb -d -v /data/tidb/data:/tmp/tidb --privilegedtrue -p 4000:4000 -p 10080:10080 pingcap/tidb:latest TiDB 简介 | PingCAP 文档中心

将您的 Ins 形象提升到新的水平

在当今这个社交媒体盛行的时代,Ins已成为人们展示个性、吸引关注的重要平台。你是否曾经想过,如果能够在同一个 Ins账户上展示不同的形象,让你的粉丝感受到更多的惊喜和乐趣呢?多账户登录功能正是满足这一需求的利器,它…

【我们常说这个pycharm里有陷阱,第三方库导入失败,看这里!】

最近有小伙伴遇到了明明安装了 python 第三方库,但是在 pycharm 当中却导入不成功的问题。 前言 一直以来,也有不少初学 python 的小伙伴,一不小心就跳进了虚拟环境和系统环境的【陷阱】中。 本文就基于此问题,来说说在 pycharm 当中如何使用系统环境、虚拟环境。 pych…

机器学习理论笔记(一):初识机器学习

文章目录 1 前言:蓝色是天的机器学习笔记专栏1.1 专栏初衷与定位1.2 本文主要内容 2 机器学习的定义2.1 机器学习的本质2.2 机器学习的分类 3 机器学习的基本术语4 探索"没有免费的午餐"定理(NFL)5 结语 1 前言:蓝色是天…

基于php动漫周边电商购物网站系统

动漫周边电商网站系统,是基于php毕业设计,mysql数据库进行开发,本系统分为用户和管理员两个角色,其中用户可以注册登陆系统,用户查看商品分类,商品列表,查看动漫周边商品详情,加入购…

【Java】BF算法(串模式匹配算法)

☀️ 什么是BF算法 BF算法,即暴力算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个与模式串T的第一个字符串进行匹配,若相等,则继续比较S的第二个字符和T的第二个字符;若不相等,则…

股票配资app是什么?是怎么一回事?

股票配资App是一种通过手机应用程序进行股票配资的工具。随着移动互联网的发展,越来越多的投资者选择使用手机进行股票交易,股票配资App应运而生。本文将对股票配资App进行详细解释。 股票配资App是一种便捷的投资工具,可以让投资者通过手机…

酷开系统 | 酷开科技大数据,更好的与目标消费人群建立联系

众所周知,OTT的一大优势在于强曝光,能够给消费者带来强烈的视觉冲击,强化品牌认知。但是,要想达到提升品牌认知,首先要保证OTT的流量规模,实现对目标人群的有效覆盖。得年轻消费者得“天下”,年…

防雷检测行业应用完整解决方案

防雷检测是指对雷电防护装置的性能、质量和安全进行检测的活动,是保障人民生命财产和公共安全的重要措施。防雷检测的作用和意义主要有以下几点: 防止或减少雷电灾害事故的发生。雷电是一种自然现象,具有不可预测、不可控制和高能量等特点&a…

spring(上)

spring是于2003年兴起的一款轻量级的,非侵入式的IOC和AOP的一站式的java开发框架,为简化企业级应用开发而生 轻量级的:指的是spring核心功能的jar包不大。 非侵入式的:业务代码不需要继承或实现spring中任何的类或接口 IOC&#x…

利用Python隧道爬虫ip轻松构建全局爬虫网络

嘿,爬虫程序员们!你们有没有碰到过需要大规模数据爬取的情况?也许你们之前遇到过网站的反爬措施,卡住你们的进度。别担心,今天我来分享一个利用Python隧道爬虫ip实现的方法,帮助你们轻松搭建全局爬虫ip网络…

Socks5代理在多线程爬虫中的应用

在进行爬虫开发过程中,我们常常需要处理大量的数据,并执行多任务并发操作。然而,频繁的请求可能会引起目标网站的反爬机制,导致IP封禁或限制访问。为了规避这些限制,我们可以借助Socks5代理的强大功能,通过…

【正点原子STM32连载】第六章 认识Geehy标准库 摘自【正点原子】APM32F407最小系统板使用指南

1)实验平台:正点原子stm32f103战舰开发板V4 2)平台购买地址:https://detail.tmall.com/item.htm?id609294757420 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html# 第六…

tk切换到mac的code分享

文章目录 前言一、基础环境配置二、开发软件与扩展1.用到的开发软件与平替、扩展情况 总结 前言 最近换上了coding人生的第一台mac,以前一直偏好tk,近来身边的朋友越来越多的用mac了,win的自动更新越来越占磁盘了,而且win11抛弃了…

c语言每日一练(8)

前言:每日一练系列,每一期都包含5道选择题,2道编程题,博主会尽可能详细地进行讲解,令初学者也能听的清晰。每日一练系列会持续更新,暑假时三天之内必有一更,到了开学之后,将看学业情…