【RT-thread studio 下使用STM32F103-学习sem-信号量-初步使用-线程之间控制-基础样例】

1、前言

最近,在使用rt-thread的时候,想要用一个线程控制另一个线程的暂停与运行,
但看资料的时候,发现删除线程和重启线程的时候,好像不太理想,这么弄是容易出现问题的,但通过信号量的方式,比较好,所以这次咱们一起来学习下sem。

自己也从新手的角度,一点点学习。整个rt-thread 还是挺大的,不是深耕多年,很难面面聚到,不过用那学哪里。

2、环境

在这里插入图片描述

3、事项了解

(1)了解sem概念-了解官网消息

大概看了一遍整个资料,还是挺多的,当你想要使用的时候,其实多少还是有些摸不到头脑的。
但既然要使用Rt-thread的,官方的文档还是要读一下。

链接:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1?id=%e4%bf%a1%e5%8f%b7%e9%87%8f
在这里插入图片描述

(2)根据自己理解,设计几个使用方式

我们使用某种RT-thread带有的功能,是为了解决我们自己出现的问题。

设计实验1:
通过使用sem信号量,当一个线程先运行后,再运行另一个线程。这样其实就是让线程之间形成先后关系,适合一定是某个线程完成后,在运行另一个线程。

设计实验2:
通过使用sem信号量,用一个线程,或者一个变量,控制或者暂停另一个线程。这样其实就是有个主线程,或不一定是主线程,可以控制其他线程运行。

以上都是小的功能模块,但是大的项目,都是小模块一点点搭建起来,这算是其中一个砖块,使用的时候,根据自己情况再调整下。

(3)不建议运行中,反复删除,在运行线程。

在看网上资料是,看到有说到,其实不建议反复挂起或删除创建线程,很容易出现问题。
当时看到了资料忘记去哪里,不过本片将有关sem信号量的。

4、实验过程

实验说明

1、第一部分实验

万事皆有要基础,一步一个脚印,如果环境不能使用的话,后续代码都是无用的,所以第一步是要搭建一个可以运行的程序。自己这块没注意,认为软件装好后,随便创建一个工程,就可以运行,没想到卡了一下。

(1)实验说明-创建工程

在这里插入图片描述

在这里插入图片描述

(2)编写代码

以下内容,RT-Thread Studio工具会自动生成的。

int main(void)
{
    int count = 1;

   
    while (count++)
    {
        LOG_D("Hello RT-Thread!");
        rt_thread_mdelay(1000);
    }

    return RT_EOK;
}
(3)验证结果

这块其实遇到一个内存相关报错,更细节部分可以看细节说明部分。
在这里插入图片描述

上述问题解决后,然后连接硬件代码,进行下载验证。
在这里插入图片描述

2、第二部分实验

(1)实验说明

此部分,主要是让一个线程先运行,运行完毕,再运行了另一个线程。在现实应用中,很多情况下,都是需要的,并且有实际意义的。

举个例子,现实中,有很多测温需求,温度过高过低,都需要做些事情,相当触发异常,这个时候,温度异常,必须先出现,才做后面事情,可以用这样逻辑解决。

(2)编写代码
/*
 * Copyright (c) 2006-2024, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-06-21     RT-Thread    first version
 */

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>


//第一步
//#include <rtthread.h>

static rt_sem_t sem; // 信号量

//第二步
void sem1_init(void)
{
    // 创建一个信号量,初始值为 0
    sem = rt_sem_create("sem", 0, RT_IPC_FLAG_FIFO);
    if (sem == RT_NULL)
    {
        rt_kprintf("create semaphore failed.\n");
    }
}
//第三步
void thread1_entry(void *parameter)
{
    while (1)
    {
        // 尝试获取信号量,如果信号量值为 0,则线程将被阻塞
        rt_sem_take(sem, RT_WAITING_FOREVER);
        rt_kprintf("Thread 1 is running.\n");
        rt_thread_mdelay(1000); // 模拟线程工作
    }
}
//第四步
void thread2_entry(void *parameter)
{
    while (1)
    {
        rt_thread_mdelay(3000); // 等待 3 秒
        rt_kprintf("Thread 2 releases semaphore.\n");
        rt_sem_release(sem); // 释放信号量
    }
}



int main(void)
{
    int count = 1;

    //第五步 应用
    sem1_init();

     // 创建线程 1
     rt_thread_t tid1 = rt_thread_create("thread1",
                                         thread1_entry, RT_NULL,
                                         1024, 10, 10);
     if (tid1 != RT_NULL)
         rt_thread_startup(tid1);

     // 创建线程 2
     rt_thread_t tid2 = rt_thread_create("thread2",
                                         thread2_entry, RT_NULL,
                                         1024, 10, 10);
     if (tid2 != RT_NULL)
         rt_thread_startup(tid2);

    while (count++)
    {
        //LOG_D("Hello RT-Thread!");
        rt_thread_mdelay(1000);
    }

    return RT_EOK;
}
(3)验证结果

如下为具体实验验证,必须是线程2运行完,才会运行线程1,是按照顺序运行。
在这里插入图片描述

3、第三部分实验

(1)实验说明

这种情况,更为复杂些,需要一个线程控制另一个线程,虽然实现方式很多,不一定非要使用这种,但是工具给你准备好了,使不使用看自己,并且是实现比较简单,实际项目,根据自己需求使用。

(2)编写代码

简单讲解下,本实验中,主要是根据a的值,来决定是否运行线程1。

/*
 * Copyright (c) 2006-2024, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-06-21     RT-Thread    first version
 */

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

//第一步
static rt_sem_t sem; // 信号量
volatile int a = 0;  // 控制变量

//第二步
void sem_init(void)
{
    // 创建一个信号量,初始值为 0
    sem = rt_sem_create("sem", 0, RT_IPC_FLAG_FIFO);
    if (sem == RT_NULL)
    {
        rt_kprintf("create semaphore failed.\n");
    }
}
//第三步
void thread1_entry(void *parameter)
{
    while (1)
    {
        // 尝试获取信号量,如果信号量值为 0,则线程将被阻塞
        rt_sem_take(sem, RT_WAITING_FOREVER);
        rt_kprintf("Thread 1 is running.\n");
        rt_thread_mdelay(1000); // 模拟线程工作
    }
}
//第四步
void thread2_entry(void *parameter)
{
    while (1)
    {
        rt_thread_mdelay(1000); // 每秒检查一次变量 a 的值

        if (a == 1)
        {
            // 如果 a == 1,则释放信号量,允许线程 1 运行
            if (rt_sem_release(sem) == RT_EOK)
            {
                rt_kprintf("Thread 2 releases semaphore.\n");
            }
        }
        else
        {
            // 如果 a == 0,则确保信号量不会释放,线程 1 将被暂停
            rt_kprintf("Thread 2: a is 0, thread 1 will pause.\n");
        }
    }
}

void set_a(int value)
{
    a = value;
    rt_kprintf("Variable a set to %d\n", a);
}


int main(void)
{
    int count = 1;

    // 初始化信号量
     sem_init();

     // 创建线程 1
     rt_thread_t tid1 = rt_thread_create("thread1",
                                         thread1_entry, RT_NULL,
                                         1024, 10, 10);
     if (tid1 != RT_NULL)
         rt_thread_startup(tid1);

     // 创建线程 2
     rt_thread_t tid2 = rt_thread_create("thread2",
                                         thread2_entry, RT_NULL,
                                         1024, 10, 10);
     if (tid2 != RT_NULL)
         rt_thread_startup(tid2);

    while (count++)
    {
        set_a(0);
        rt_thread_mdelay(10000);
        set_a(1);
        //LOG_D("Hello RT-Thread!");
        rt_thread_mdelay(10000);
    }

    return RT_EOK;
}
(3)验证结果

在这里插入图片描述

5、代码链接

代码链接:https://download.csdn.net/download/qq_22146161/89466496

6、细节部分

1、dome 文件报错

在这里插入图片描述
在这里插入图片描述

7、总结

一个砖一个砖,垒起来。

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

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

相关文章

DataWhale-吃瓜教程学习笔记 (七)

学习视频**&#xff1a;第6章-支持向量机_哔哩哔哩_bilibili 西瓜书对应章节&#xff1a; 第六章 支持向量机 - 算法原理 几何角度 对于线性可分数据集&#xff0c;找距离正负样本距离都最远的超平面&#xff0c;解是唯一的&#xff0c;泛化性能较好 - 超平面 - 几何间隔 例…

堆叠的作用

一、为什么要堆叠 传统的园区网络采用设备和链路冗余来保证高可靠性&#xff0c;但其链路利用率低、网络维护成本高&#xff0c;堆叠技术将多台交换机虚拟成一台交换机&#xff0c;达到简化网络部署和降低网络维护工作量的目的。 二、堆叠优势 1、提高可靠性 堆叠系统多台成…

ServiceImpl中的参数封装为Map到Mapper.java中查询

ServiceImpl中的参数封装为Map到Mapper.java中查询&#xff0c;可以直接从map中获取到key对应的value

【Python机器学习】处理文本数据——多个单词的词袋(n元分词)

使用词袋表示的主要缺点之一就是完全舍弃了单词顺序。因此“its bad&#xff0c;not good at all”和“its good&#xff0c;not bad at all”这两个字符串的词袋表示完全相同&#xff0c;尽管它们的含义相反。幸运的是&#xff0c;使用词袋表示时有一种获取上下文的方法&#…

LeetCode热题100刷题3:3. 无重复字符的最长子串、438. 找到字符串中所有字母异位词、560. 和为 K 的子数组

3. 无重复字符的最长子串 滑动窗口、双指针 class Solution { public:int lengthOfLongestSubstring(string s) {//滑动窗口试一下//英文字母、数字、符号、空格,ascii 一共包含128个字符vector<int> pos(128,-1);int ans 0;for(int i0,j0 ; i<s.size();i) {//s[i]…

全端面试题15(canvas)

在前端开发领域&#xff0c;<canvas> 元素和相关的 API 是面试中经常被提及的主题。下面是一些常见的关于 HTML5 Canvas 的面试问题及解答示例&#xff1a; 1. 什么是 <canvas> 元素&#xff1f; <canvas> 是 HTML5 引入的一个用于图形渲染的标签。它本身并…

能否免费使用Adobe XD?

Adobe XD不是免费的。Adobe 目前XD采用订阅模式&#xff0c;提供订阅模式 7 每天试用期结束后需要付费购买&#xff0c;具体价格根据不同的订阅计划确定&#xff0c;包括每月购买&#xff0c;包括 9.99 美元或每月 99.99 美元&#xff0c;或者选择购买Adobe CreativeCloud整体订…

【qt】如何通过域名获得IP地址?

域名是什么呢?像www.baidu.com的baidu.com就是域名. 域名相当于是网站的门牌号. 域名可以通过 DNS 解析将其转换为对应的 IP 地址. 用我们获取IP地址的方式就可以,但是现在没有可以用另一种方法. 槽函数的实现: void MainWindow::lookupHost(const QHostInfo &hostInf…

Python学习笔记29:进阶篇(十八)常见标准库使用之质量控制中的数据清洗

前言 本文是根据python官方教程中标准库模块的介绍&#xff0c;自己查询资料并整理&#xff0c;编写代码示例做出的学习笔记。 根据模块知识&#xff0c;一次讲解单个或者多个模块的内容。 教程链接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 质量控制…

RedHat / CentOS安装FTP服务

本章教程,记录在RedHat / CentOS中安装FTP的具体步骤。FTP默认端口:21 1、安装 epel 源 yum install -y epel-release2、安装 pure-ftpd yum -y install pure-ftpd3、修改默认配置 # 默认配置位于 /etc/pure-ftpd/pure-ftpd.conf,在配置文件中找到下面几个参数进行修改:#…

并发、多线程和HTTP连接之间有什么关系?

一、并发的概念 并发是系统同时处理多个任务或事件的能力。在计算中&#xff0c;这意味着系统能够在同一时间段内处理多个任务&#xff0c;而不是严格按照顺序一个接一个地执行它们。并发提高了系统的效率和资源利用率&#xff0c;从而更好地满足用户的需求。在现代应用程序中&…

C++ windows下使用openvino部署yoloV8

目录 准备版本&#xff1a; 准备事项: 选择配置界面&#xff1a; 下载界面&#xff1a; ​编辑 添加VS配置&#xff1a; 准备代码&#xff1a; yolov8.h yolov8.cpp detect.cpp 如何找到并放置DLL&#xff1a; 准备版本&#xff1a; opencv 4.6.0 openvino 2024.0…

深度解读:Etched Sohu与Groq LPU芯片的区别

本文简单讲解一下Etched Sohu与Groq LPU两种芯片的区别。 设计理念的差异 首先&#xff0c;这两款产品在设计理念上完全是两条不同的路线。Etched Sohu芯片的设计理念是围绕Transformer模型进行优化。Transformer模型近年来在NLP任务中表现出色&#xff0c;Etched公司因此为其…

SpringSecurity中文文档(Servlet Password Storage)

存储机制&#xff08;Storage Mechanisms&#xff09; 每种支持的读取用户名和密码的机制都可以使用任何支持的存储机制&#xff1a; Simple Storage with In-Memory AuthenticationRelational Databases with JDBC AuthenticationCustom data stores with UserDetailsServic…

4个免费文章生成器,为你免费一键生成原创文章

在当今的创作领域&#xff0c;创作者们常常陷入各种困境。灵感的缺失、内容创新的压力&#xff0c;每一项都如同沉重的枷锁&#xff0c;束缚着他们的创作步伐。但随着免费文章生成器的出现&#xff0c;宛如一场及时雨&#xff0c;为创作者们带来了新的希望和转机。免费文章生成…

【ABB】原点设定

【ABB】原点设定 操作流程演示 操作流程 操作轴回原点编辑电机校准偏移更新转速计数器 1.首先得了解机器手的轴&#xff0c;这里以6轴作参考。 注意先回456轴&#xff0c;后回123轴。 2.然后需要了解机器人关节运动模式&#xff0c;即选择如下两个模式。 3.注意机器人各轴移动…

19C 单机文件系统安装文档

准备工作 1)查看系统版本、内核参数 more /etc/redhat-release more /etc/redflag-releaseuname -a2)查看当前系统是否配置了HugePages。在下面的查询中&#xff0c;HugePages的几个相关值都为0&#xff0c;表明当前未配值HugePages&#xff0c;其次可以看到该版本的大页大小为…

Linux服务器性能参数指标

【摘要】一个基于 Linux 操作系统的服务器运行的同时&#xff0c;会表征出各种各样参数信息&#xff0c;这些蛛丝马迹往往会帮助快速定位跟踪问题。 这里只是一些简单的工具查看系统的相关参数&#xff0c;当然很多工具也是通过分析加工 /proc、/sys 下的数据来工作的&#xff…

课设:选课管理系统(Java+MySQL)

在本博客中&#xff0c;我将介绍用Java、MySQL、JDBC和Swing GUI开发一个简单的选课管理系统。 技术栈 Java&#xff1a;用于编写应用程序逻辑MySQL&#xff1a;用于存储和管理数据JDBC&#xff1a;用于连接Java应用程序和MySQL数据库Swing GUI&#xff1a;用于构建桌面应用程…

RH850系列芯片深度剖析 1.8-内存管理之MPU

RH850系列芯片深度剖析 1.8-内存管理之MPU 文章目录 RH850系列芯片深度剖析 1.8-内存管理之MPU一、MPU简介1.1 功能特性1.2 系统保护标识符(SPID)二、保护区域设置2.1 保护区域属性设置2.2 保护区域设置注意事项2.2.1 跨越保护区域边界2.2.2 无效的保护区域设置2.2.3 保护违规…