【STM32RT-Thread零基础入门】 6. 线程创建应用(线程挂起与恢复)

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

文章目录

  • 前言
  • 一、RT-Thread相关接口函数
    • 1. 挂起线程
    • 2. 恢复线程
  • 二、程序设计
    • 1. car_led.c
    • 2.car_led.h
    • 3. main.c
  • 三、程序测试
  • 总结


前言

在上一个任务中,通过停止命令把线程删除后,线程在系统中就不存在了,也无法再使线程重新运行。例如输入stop_led_thread命令后,led停止闪烁,但也无法重新开启LED灯闪烁功能。本任务通过修改停止命令的实现代码,同时增加恢复命令,使led灯闪烁功能可以暂停和恢复。


一、RT-Thread相关接口函数

1. 挂起线程

线程挂起是指把线程脱离就绪队列,使线程不参与调度器的调度。线程挂起使用下面的接口函数:

rt_err_t rt_thread_suspend (rt_thread_t thread);

线程挂起接口 rt_thread_suspend() 的参数和返回值见下表:

参数描述
thread线程句柄
返回RT_EOK: 线程挂起成功,-RT_ERROR: 线程挂起失败,因为该线程的状态并不是就绪状态

注:一个线程尝试挂起另一个线程是一个非常危险的行为,因此RT-Thread对此函数有严格的使用限制:该函数只能使用来挂起当前线程(即自己挂起自己),不可以在线程A中尝试挂起线程B。而且在挂起线程自己后,需要立刻调用 rt_schedule() 函数进行手动的线程上下文切换。用户只需要了解该接口的作用即可,不建议在程序中使用该接口。该接口可以视为是内部接口。这是因为A线程在尝试挂起B线程时,A线程并不清楚B线程正在运行什么程序,一旦B线程正在使用影响、阻塞其他线程(如C线程)的内核对象(例如互斥量、信号量等)时,如果此时其他线程也在等待这个内核对象,那么A线程尝试挂起B线程的操作将会引发其他线程(如C线程)的饥饿,严重危及系统的实时性。有些地方会将其描述为死锁,实际上这种现象不是死锁,但是也没有比死锁好到哪去。

当线程调用 rt_thread_delay() 时,线程将主动挂起;当调用 rt_sem_take(),rt_mb_recv() 等函数时,资源不可使用也将导致线程挂起。处于挂起状态的线程,如果其等待的资源超时(超过其设定的等待时间),那么该线程将不再等待这些资源,并返回到就绪状态;或者,当其他线程释放掉该线程所等待的资源时,该线程也会返回到就绪状态。

2. 恢复线程

恢复线程就是让挂起的线程重新进入就绪状态,并将线程放入系统的就绪队列中;如果被恢复线程在所有就绪态线程中,位于最高优先级链表的第一位,那么系统将进行线程上下文的切换。线程恢复使用下面的函数接口:

rt_err_t rt_thread_resume (rt_thread_t thread);

线程恢复接口 rt_thread_resume() 的参数和返回值见下表:

参数描述
thread线程句柄
返回RT_EOK: 线程恢复成功,-RT_ERROR: 线程恢复失败,因为该个线程的状态并不是 RT_THREAD_SUSPEND 状态

二、程序设计

在前一章节的基础上修改car_led.c、car_led.h和main.c三个文件即可,具体如下:

1. car_led.c

增加暂停标志、暂停设置接口,以及在线程中增加暂停执行代码

#include <rtthread.h>
#include <rtdevice.h>
#include "drv_common.h"

#define DBG_TAG "LED"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include <stdlib.h>
#include "car_led.h"
/* 定义左右转向灯的控制引脚 */
#define LedLeft GET_PIN(D, 8)
#define LedRight GET_PIN(D, 9)
#define LedOn(pin) rt_pin_write(pin, PIN_LOW)
#define LedOff(pin) rt_pin_write(pin, PIN_HIGH)

enum led_mode LedMod=LED_MODE_STOP;
void led_set_mode(enum led_mode m)
{
    LedMod = m;
}
/* 暂停运行标志变量,0表示运行,1表示暂停 */
static int stopFlag=0;
void led_thread_entry()
{
    rt_pin_mode(LedLeft, PIN_MODE_OUTPUT);
    rt_pin_mode(LedRight, PIN_MODE_OUTPUT);
while(1){
    /*判断是否暂停运行*/
        if(stopFlag)
        {
            rt_thread_suspend(rt_thread_self());//挂起线程,只能自已挂起自已
            rt_schedule();//使用suspend挂起线程后,需手动进行线程上下文切换
        }
        switch(LedMod)
        {
        case LED_MODE_STOP:
            LedOff(LedLeft);
            LedOff(LedRight);
            break;
        case LED_MODE_Double:
            LedOn(LedLeft);
            LedOn(LedRight);
            rt_thread_mdelay(500);
            LedOff(LedLeft);
            LedOff(LedRight);
            break;
        case LED_MODE_LEFT:
            LedOff(LedRight);
            LedOn(LedLeft);
            rt_thread_mdelay(250);
            LedOff(LedLeft);
            break;
        case LED_MODE_RIGHT:
            LedOff(LedLeft);
            LedOn(LedRight);
            rt_thread_mdelay(250);
            LedOff(LedRight);
            break;
        default:
            LOG_D("mode error\n");
        }
        rt_thread_mdelay(250);
    }
}
void ledmode(int argn, char *argv[])
{
    if(argn<2){
        LOG_W("ledmode #mode");
        return ;
    }
    led_set_mode(atoi(argv[1]));

}
void led_stop_flag(int i)//设置暂停标志的接口
{
    stopFlag=i;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(ledmode, set led flash mode);

2.car_led.h

代码如下:

#ifndef APPLICATIONS_CAR_LED_H_
#define APPLICATIONS_CAR_LED_H_

/* 车灯闪烁模式定义 */
enum led_mode {
    LED_MODE_STOP=0, //停止闪烁
    LED_MODE_Double, //双闪
    LED_MODE_LEFT,   //左灯闪烁
    LED_MODE_RIGHT   //右灯闪烁
};
void led_thread_entry();               //线程入口函数声明
void led_set_mode(enum led_mode m);    //车灯闪烁模式设置声明
void led_stop_flag(int i); //接口声明,同时导出模块接口供其它模块使用

#endif /* APPLICATIONS_CAR_LED_H_ */

3. main.c

主要修改stop_led_thread()函数的实现,同时增加线程恢复函数,并把线程恢复函数导出到msh命令中,使我们可以通过终端来恢复线程。

#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     20     //定义线程优先级
#define THREAD_TIMESLICE    10     //定义线程时间片

/* 栈首地址必须系统对齐 */
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;

    /* 动态方式创建线程 */
    TidLed = rt_thread_create("LED", 
								led_thread_entry, 
								RT_NULL,
								THREAD_STACK_SIZE, 
								THREAD_PRIORITY, 
								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,
                            THREAD_TIMESLICE);
    if (ret == RT_EOK) //判断线程是否成功创建
        rt_thread_startup(&beepThread); //成功则启动线程
    else { //否则打印日志并即出
        LOG_D("can not init beep thread!");
        return -1;
    }

    return RT_EOK;
}
void stop_led_thread()//暂停运行
{
     led_stop_flag(1);
}
void resume_led_thread()//恢复运行
{
    led_stop_flag(0);//先设置为运行
    rt_thread_resume(TidLed);//再恢复线程
    return;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(resume_led_thread, resume led thread);//唤醒命令
MSH_CMD_EXPORT(stop_led_thread, stop led thread);

三、程序测试

(1)系统启动后,使用命令“ledmode 1”使能车灯双闪,观察到车灯闪烁。
在这里插入图片描述
(2)输入命令“stop_led_thread”命令,观察到车灯停止闪烁,说明线程已经被挂起。
在这里插入图片描述
(3)输入命令“resume_led_thread”命令,观察到车灯重新闪烁,说明线程被重新唤醒。
在这里插入图片描述
(4)输入命令“ps”命令,如图所示,观察到BEEP和LED两个线程都处理挂起状态,这主要是因为ps命令输出时,CPU正在运行tshell程序(命令是在tshell线程上下文件中运行的),而此时BEEP和LED两个线程因为执行rt_thread_mdelay()函数而被挂起。
在这里插入图片描述


总结

本章节学习线程的挂起与恢复的应用

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【QML】鼠标放在控件上颜色改变的效果实现

最近刚好要用到一个功能&#xff0c;在qml上实现鼠标放上去&#xff0c;控件的颜色改变&#xff0c;鼠标移走&#xff0c;控件颜色恢复。第一反应是这个功能非常简单&#xff0c;但是搞了一会儿都没实现&#xff0c;最后发现MouseArea其实提供了一个很简便的方法来提供使用&…

PHP反序列化 字符串逃逸

前言 最近在打西电的新生赛&#xff0c;有道反序列化的题卡了很久&#xff0c;今天在NSS上刷题的时候突然想到做法&#xff0c;就是利用字符串逃逸去改变题目锁死的值&#xff0c;从而实现绕过 为了研究反序列化的字符串逃逸 我们先简单的测试下 原理 <?php class escape…

学习平台助力职场发展与提升

近年来&#xff0c;随着互联网技术的发展&#xff0c;学习平台逐渐成为了职场发展和提升的必备工具。学习平台通过提供丰富的课程内容、灵活的学习时间和个性化的学习路径&#xff0c;帮助职场人士更好地提升自己的技能和知识储备&#xff0c;为职场发展打下坚实的基础。 学习…

软件测试(黑皮书)学习一

第一部分 软件测试综述 第一章 软件测试背景 1.1软件缺陷&#xff08;software bug&#xff09; 软件失败的术语 故障&#xff08;fault&#xff09;失败&#xff08;failure&#xff09; 缺点&#xff08;defect&#xff09; ------严重、危险异常&#xff08;anomaly&…

基于 Alpine 环境源码构建 alibaba-tengine(阿里巴巴)的 Docker 镜像

About Alpine&#xff08;简介&#xff09; Alpine Linux 是一款极其轻量级的 Linux 发行版&#xff0c;基于 busybox&#xff0c;多被当做 Docker 镜像的底包&#xff08;基础镜像&#xff09;&#xff0c;在使用容器时或多或少都会接触到此系统&#xff0c;本篇文章我们以该镜…

【Go语言】基于Socket编程的P2P通信程序示例

Go语言的Socket编程实现为开发者提供了一种高效且强大的方式来实现网络通信。通过Go语言的并发模型和内置的网络库&#xff0c;如net包&#xff0c;开发者可以轻松地创建基于套接字的通信应用。Go语言的goroutine和channel机制使并发处理变得简单&#xff0c;能够轻松处理多个连…

leetcode 125.验证回文串

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;https://leetcode.cn/problems/valid-palindrome/ 思路&#xff1a; 这道题只判断字符串中的字母与数字是否是回文。虽然小写大写字母可以互相转换&#xff0c;但是里面是含有数字字符的&#xff0c;所以先统一&#xff…

排序算法合集

F B I W a r n i n g : \color{red}FBI \qquad Warning: FBIWarning: 本人没有完整的计算机科班的教育经历&#xff0c;但是一直在兢兢业业&#xff0c;努力学习。 这些排序函数都是自己零零散散写的&#xff0c;也没有经过深思熟虑和优化&#xff0c;纯粹是为了自娱自乐。 …

node使用高版本的oracledb导致连接oracle的Error: NJS-138异常

异常信息如下 Error: NJS-138: connections to this database server version are not supported by node-oracledb in Thin mode 我的oracle版本是11g&#xff0c;之前的使用正常&#xff0c;今天却报错了&#xff0c;显示不支持thin模式&#xff0c;后面回退版本就可以了。

AWS复制EC2文件到S3,g4dn.2xlarge没有NVIDIA GPU 驱动问题

1、给instances权限 action > Security > modify IAM role 把提前创建好的role给这个instance即可 2、复制到bucket aws s3 cp gogo.tar.gz s3://ee547finalbucket不需要手动安装GPU驱动 如果要自己安装&#xff0c;参考https://docs.aws.amazon.com/AWSEC2/latest/U…

6-模板初步使用

官网: 中文版: 介绍-Jinja2中文文档 英文版: Template Designer Documentation — Jinja Documentation (2.11.x) 模板语法 1. 模板渲染 (1) app.py 准备数据 import jsonfrom flask import Flask,render_templateimport settingsapp Flask(__name__) app.config.from_obj…

C#详解-Contains、StartsWith、EndsWith、Indexof、lastdexof

目录 简介: 过程: 举例1.1 举例1.2 ​ 总结: 简介: 在C#中Contains、StarsWith和EndWith、IndexOf都是字符串函数。 1.Contains函数用于判断一个字符串是否包含指定的子字符串&#xff0c;返回一个布尔值&#xff08;True或False&#xff09;。 2.StartsWith函数用于判断一…

wifi高通驱动之WCNSS_qcom_cfg.ini以及MCS、空间流数的学习和记录

一、WCNSS_qcom_cfg.ini 这个文件说是可以调优wifi的带宽&#xff0c;还有MIMO技术 Android Wi-Fi MIMO/SISO设置方法&#xff08;基于高通平台&#xff09;_广凯的博客-CSDN博客 不是太了解&#xff0c;先记录一下&#xff0c;个人感觉MCS和MIMO技术最全的应该是下面的网址…

DataLoader PyTorch 主要参数的含义

定义&#xff1a; DataLoader类是一个用于从数据集&#xff08;dataset&#xff09;中加载数据&#xff0c;并以迭代器&#xff08;iterator&#xff09;的形式返回数据样本&#xff08;data samples&#xff09;的工具。您给出的两个字典&#xff08;dictionary&#xff09;分…

%f占位符

介绍&#xff1a; %f &#xff0c;用来输出实数&#xff08;包括单双精度&#xff09;&#xff0c;以小数形式输出。 通常情况下&#xff0c;当输入的数值或者打印的数值是float类型数据时&#xff0c;使用%f &#xff0c;当然在精度更高的double数据类型下&#xff0c;也可以…

记忆正则表达式的基本元件

正则常见的三种功能&#xff0c;它们分别是&#xff1a;校验数据的有效性、查找符合要求的文本以及对文本进行切割和替换等操作。 正则表达式&#xff0c;简单地说就是描述字符串的规则。在正则中&#xff0c;普通字符表示的还是原来的意思&#xff0c;比如字符 a&#xff0c;…

Linux下的Shell编程——正则表达式入门(四)

前言&#xff1a; 正则表达式使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。在很多文本编辑器里&#xff0c;正则表达式通常被用来检索、替换那些符合某个模式的文本。 在Linux 中&#xff0c;grep&#xff0c;sed&#xff0c;awk 等文本处理工具都支持…

Spring Clould 服务间通信 - Feign

视频地址&#xff1a;微服务&#xff08;SpringCloudRabbitMQDockerRedis搜索分布式&#xff09; Feign-基于Feign远程调用&#xff08;P30&#xff09; 先来看我们以前利用RestTemplate发起远程调用的代码&#xff1a; 存在下面的问题&#xff1a; 代码可读性差&#xff0c…

在外SSH远程连接macOS服务器

文章目录 前言1. macOS打开远程登录2. 局域网内测试ssh远程3. 公网ssh远程连接macOS3.1 macOS安装配置cpolar3.2 获取ssh隧道公网地址3.3 测试公网ssh远程连接macOS 4. 配置公网固定TCP地址4.1 保留一个固定TCP端口地址4.2 配置固定TCP端口地址 5. 使用固定TCP端口地址ssh远程 …

PSP - 基于开源框架 OpenFold Multimer 蛋白质复合物的结构预测与BugFix

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132410296 AlphaFold2-Multimer 是一个基于 AlphaFold2 的神经网络模型&#xff0c;可以预测多链蛋白复合物的结构。该模型在训练和推理时都可以处…