【STM32&RT-Thread零基础入门】 7. 线程创建应用(多线程运行机制)

这篇具有很好参考价值的文章主要介绍了【STM32&RT-Thread零基础入门】 7. 线程创建应用(多线程运行机制)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

硬件:STM32F103ZET6、ST-LINK、usb转串口工具、4个LED灯、1个蜂鸣器、4个1k电阻、2个按键、面包板、杜邦线


前言

本章进一步研究多线程的运行机制。要求实现功能如下:创建2个线程,线程名称分别为LED和BEEP。两个线程的任务是连续5次打印本线程的名字后退出线程(注意:线程不执行控制LED和蜂鸣器动作)。

设计本任务的目的是观察LED和BEEP线程在操作系统中是如何同时运行的。


一、RT-Thread相关接口函数

1. 获取当前运行的线程

在程序的运行过程中,相同的一段代码可能会被多个线程执行,在执行的时候可以通过下面的函数接口获得当前执行的线程句柄:

rt_thread_t rt_thread_self(void);

该接口的返回值见下表:

返回 描述
thread 当前运行的线程句柄
返回 RT_NULL:失败,调度器还未启动

2. 设置调度器钩子函数

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

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

设置调度器钩子函数的输入参数如下表所示:

参数 描述
hook 表示用户定义的钩子函数指针

钩子函数 hook() 的声明如下:

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

调度器钩子函数 hook() 的输入参数如下表所示:

函数参数 描述
from 表示系统所要切换出的线程控制块指针
to 表示系统所要切换到的线程控制块指针

注:请仔细编写你的钩子函数,稍有不慎将很可能导致整个系统运行不正常(在这个钩子函数中,基本上不允许调用系统 API,更不应该导致当前运行的上下文挂起)。

二、程序设计

使用rt_thread_t rt_thread_self()函数获取本线程的线程句柄,然后通过线程句柄,可以方便地获得线程地名称。对main.c进行如下程序设计

1. 头文件包含及宏定义

本任务代码中,我们使用预编译宏进行选择编译,使代码可以兼容两个版本,提高代码利用率

#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
//#include "car_led.h"    //包含LED控制模块头文件
//#include "car_beep.h"   //包含蜂鸣器控制模块头文件


#define THREAD_STACK_SIZE   1024   //定义线程栈大小
//两个线程优先级分别定义
#define THREAD_PRIORITY_LED     20     
#define THREAD_PRIORITY_BEEP     20     
#define THREAD_TIMESLICE    10     //定义线程时间片

/*使用预编译宏进行选择编译,当定义以下宏时,讲开启调度器钩子功能*/
//#define SCHEDULER_HOOK

#ifdef SCHEDULER_HOOK
//定义调度钩子函数
static void hook_of_scheduler(struct rt_thread* from,struct rt_thread* to)
{
    //打印调度信息:从一个线程切换到另一个线程运行
    rt_kprintf("from: %s --> to: %s \n",from->name,to->name);
}
#endif

2. 线程入口函数定义

本任务需要创建两个线程,所以要编写两个线程入口函数,分别为beep_thread_entry和led_thread_entry。

void beep_thread_entry(void * parameter)
{
    rt_thread_t tid;
    int count = 0;      //打印出前5个调度过程
    
    while(1){
        tid =rt_thread_self();  //获取本线程地句柄
        //打印线程的名字和当前计数变量地值
        LOG_D("thread name: %s count = %d\n",tid->name,count);
        if (count++ ==5)        //线程循环5次后退出 
            break;   
    }
    //线程退出时打印退出信息
    LOG_D("thread %s exit\n",tid->name);
}

void led_thread_entry()
{
    rt_thread_t tid;
    int count = 0;      //打印出前5个调度过程
    
    while(1){
        tid =rt_thread_self();  //获取本线程地句柄
        //打印线程的名字和当前计数变量地值
        LOG_D("thread name: %s count = %d\n",tid->name,count);
        if (count++ ==5)        //线程循环5次后退出 
            break;   
    }
    //线程退出时打印退出信息
    LOG_D("thread %s exit\n",tid->name);
}

3. main函数设计

main只负责线程的创建,用动态的方法创建LED线程,静态方法创建beep线程。静态方法需要用户自定义线程栈空间和线程控制块。

/* 栈首地址必须系统对齐 */
ALIGN(RT_ALIGN_SIZE)
static char beep_stack[THREAD_STACK_SIZE];  //定义栈空间
static struct rt_thread beepThread;    //静态方式定义beep线程控制块
rt_thread_t TidLed = RT_NULL;  //动态方式定义LED线程句柄

int main(void)
{
    int ret;

#ifdef SCHEDULER_HOOK
//设置调度钩子
    rt_scheduler_sethook(hook_of_scheduler);

#endif

    /* 动态方式创建线程 */
    TidLed = rt_thread_create("LED", 
								led_thread_entry, 
								RT_NULL,
								THREAD_STACK_SIZE, 
								THREAD_PRIORITY_LED,
								THREAD_TIMESLICE);
    if (TidLed != RT_NULL)//判断线程是否成功创建
        rt_thread_startup(TidLed);//成功则启动线程
    else {//否则打印日志并即出
        LOG_D("can not create LED thread!");
        return -1;
    }

    /* 采用静态方式初始化线程 */
    ret = rt_thread_init(&beepThread,
                            "BEEP",
                            beep_thread_entry,
                            RT_NULL,
                            &beep_stack[0],
                            sizeof(beep_stack),
                            THREAD_PRIORITY_BEEP,
                            THREAD_TIMESLICE);
    if (ret == RT_EOK) //判断线程是否成功创建
        rt_thread_startup(&beepThread); //成功则启动线程
    else { //否则打印日志并即出
        LOG_D("can not init beep thread!");
        return -1;
    }

    return RT_EOK;
}

三、程序测试

(1)使用终端连接开发板,然后按开发板reset键重启系统,终端调试信息如下图,发现两个线程轮流输出信息,可以间接说明两个线程时轮流执行的。
stm32多线程,STM32 RT-Thread操作系统入门,stm32,嵌入式硬件,单片机
(2)把BEEP优先级改为19,修改后按照(1)进行测试,如图所示,即使LED线程先于BEEP线程创建,由于BEEP线程的优先级高于LED线程,因此BEEP线程被执行,LED要等BEEP执行完后再执行。
stm32多线程,STM32 RT-Thread操作系统入门,stm32,嵌入式硬件,单片机
(3)打开预处理宏定义#define SCHEDULER_HOOK,把LED和BEEP优先级都设置为20,重新构建并下载。由下图可以看到,系统先运行main线程,再运行tshell线程,这是因为系统中main线程优先级默认为10,比tshell默认优先级20高,所以系统先运行main线程。

tshell运行后LED线程和BEEP线程接着轮流运行,由于这3个线程的优先级都是20,所以他们在属于同一个优先级的队列中,并且按启动先后顺序排列(注意:是启动顺序,即rt_thread_startup()函数的执行顺序,而不是创建程序),调度顺序也是按照启动的先后顺序进行的。

LED线程和BEEP线程退出后,进入tidle0线程运行,tidle0优先级在系统中最低,当所有高优先级的线程退出或者睡眠时,会进入tidle0线程运行。
stm32多线程,STM32 RT-Thread操作系统入门,stm32,嵌入式硬件,单片机
(4)打开预处理宏定义#define SCHEDULER_HOOK,把LED和BEEP优先级分别设置为20、19。
修改后重新构建并下载程序,观察终端如图所示。系统运行顺序为:
main线程→BEEP线程→tshell线程→LED线程
stm32多线程,STM32 RT-Thread操作系统入门,stm32,嵌入式硬件,单片机


总结

在操作系统中,所有线程各自独立运行,所有线程看起来是同时工作的,但在只有一个CPU核的情况下,在同一时刻只能有一个线程在CPU上运行,操作系统为每个线程分配一定的运行时间片,当线程的运行时间耗尽时,操作系统会调度下一个线程到CPU运行。由于时间片很小,使得我们觉得线程是在同时运行的。文章来源地址https://www.toymoban.com/news/detail-778050.html

到了这里,关于【STM32&RT-Thread零基础入门】 7. 线程创建应用(多线程运行机制)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【STM32&RT-Thread零基础入门】8. 基于 CubeMX 移植 RT-Thread Nano

    硬件:STM32F103ZET6、ST-LINK、usb转串口工具、4个LED灯、1个蜂鸣器、4个1k电阻、2个按键、面包板、杜邦线 利用RT_Thread操作系统实现三种不同的LED等闪烁 提示:以下是本篇文章正文内容,下面案例可供参考 cubemx配置参考教程: 基于 CubeMX 移植 RT-Thread Nano 后面程序所需的引脚 RT

    2024年02月09日
    浏览(36)
  • 【STM32&RT-Thread零基础入门】 3. PIN设备(GPIO)的使用

    硬件:STM32F103ZET6、ST-LINK、usb转串口工具、4个LED灯、1个蜂鸣器、4个1k电阻、2个按键、面包板、杜邦线 在嵌入式系统中,GPIO是最常用的一种设备,在RT-Thread操作系统中,把GPIO命名为PIN设备。 RT-Thread通过PIN设备对芯片的GPIO引脚进行管理,应用程序可以通过其提供的一组PIN设备

    2024年02月13日
    浏览(39)
  • STM32CubeMX+VSCODE+EIDE+RT-THREAD 工程创建

            Eide环境搭建暂且不表,后续补充。主要记录下Vscode环境下 创建Rt-thread工程的过程。分别介绍STM32CubeMX添加rtt支持包的方式和手动添加rtt kernel方式。STM32CubeMX生成工程的时候有\\\"坑\\\",防止下次忘记,方便渡一下有缘人,特此记录。         此工程以创建stm32f405为例

    2024年02月14日
    浏览(39)
  • RT-Thread:STM32实时时钟 RTC开启及应用

    说明: STM32F103/407系列基于 RT-Thread 系统的 RTC 开启及应用 应用流程介绍。 完成以上系统配置,编译无误情况下RTC 就已经开启了。 官方 API 查询地址:https://www.rt-thread.org/document/api/rtc_sample_8c-example.html#a3 1.设置日期:设置系统日期但不修改时间 2.设置时间:设置系统时间但不

    2024年01月17日
    浏览(54)
  • 使用RT-Thread Studio搭配STM32CubeMX新建RT-Thread项目

    STM32CubeMX下载 RT-Thread Studio下载 安装好RT-Thread Studio后,先打开RT-Thread SDK管理器确认有没有自己MCU需要的SDK包,直接安装好之后里面是有STM32F1系列的SDK包,其他的需要自己安装。 之后点击文件→新建→RT-Thread项目,根据自己需要配置好后点击完成就会生成RT-Thread项目。 新建项

    2024年02月11日
    浏览(41)
  • Rt-Thread 移植5--空闲线程和线程阻塞(KF32)

    src中定义idle.c clock.c 5.3.6 中断函数 irq.c main.c

    2024年02月06日
    浏览(34)
  • [嵌入式系统-32]:RT-Thread -17- 任务、进程、线程的区别

    目录 一、基本概念澄清 1.1 任务 1.2 进程 1.3 线程 1.4 比较 1.5 任务VS进程 1.6 进程 VS 线程 1.7 任务 进程 线程 发展历史 任务(Task): 进程(Process): 线程(Thread): 发展趋势: 二、不同操作系统中任务、进程、线程 2.1 Linux:没人任务,只有进程与线程 进程相关函数: 线程

    2024年02月21日
    浏览(36)
  • STM32 + RT-Thread + LwIp + DM9000

    开发板:STM32F103ZET6(战舰) RT-Thread:5.0.0 LwIp:2.1.2 网卡芯片:DM9000 编译环境:keil 我简单了解了一下,在嵌入式中,网络芯片的使用方式大致有三种,如下: (MCU + MAC + PHY) (MUC + MAC) —— PHY MCU —— (MAC + PHY) 注意: 我用括号里面的表示在同一块芯片中 移植 RT-Thread 不是此文

    2024年02月07日
    浏览(41)
  • RT-Thread入门笔记5-线程的时间片轮询调度

    优先级和时间片是线程的两个重要参数,优先级描述了线程竞争处理器资源的能力。 优先级和时间片 优先级 RT-Thread 最大支持 256 个优先级(数值越小的优先级越高,0 为最高优先级, 最低优先级预留给空闲线程);用户可以通过rt_config.h中的RT_THREAD_PRIORITY_MAX宏来修改最大支持

    2024年02月02日
    浏览(35)
  • RT-Thread STM32 GoKit V2.1 开发板BSP说明

    本文档为刘恒为 GoKit V2.1 开发板提供的 BSP (板级支持包) 说明。 主要内容如下: 开发板资源介绍 BSP 快速上手 进阶使用方法 通过阅读快速上手章节开发者可以快速地上手该 BSP,将 RT-Thread 运行在开发板上。在进阶使用指南章节,将会介绍更多高级功能,帮助开发者利用 RT-

    2024年02月04日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包