【RT-thread studio 下使用STM32F103-学习sem-信号量-初步使用-线程之间控制-基础样例】
【RT-thread studio 下使用STM32F103-学习sem-信号量-初步使用-线程之间控制-基础样例】
- 1、前言
- 2、环境
- 3、事项了解
- (1)了解sem概念-了解官网消息
- (2)根据自己理解,设计几个使用方式
- (3)不建议运行中,反复删除,在运行线程。
- 4、实验过程
- 实验说明
- 1、第一部分实验
- (1)实验说明-创建工程
- (2)编写代码
- (3)验证结果
- 2、第二部分实验
- (1)实验说明
- (2)编写代码
- (3)验证结果
- 3、第三部分实验
- (1)实验说明
- (2)编写代码
- (3)验证结果
- 5、代码链接
- 6、细节部分
- 1、dome 文件报错
- 7、总结
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)
{// 创建一个信号量,初始值为 0sem = 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();// 创建线程 1rt_thread_t tid1 = rt_thread_create("thread1",thread1_entry, RT_NULL,1024, 10, 10);if (tid1 != RT_NULL)rt_thread_startup(tid1);// 创建线程 2rt_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)
{// 创建一个信号量,初始值为 0sem = 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();// 创建线程 1rt_thread_t tid1 = rt_thread_create("thread1",thread1_entry, RT_NULL,1024, 10, 10);if (tid1 != RT_NULL)rt_thread_startup(tid1);// 创建线程 2rt_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、总结
一个砖一个砖,垒起来。
相关文章:
【RT-thread studio 下使用STM32F103-学习sem-信号量-初步使用-线程之间控制-基础样例】
【RT-thread studio 下使用STM32F103-学习sem-信号量-初步使用-线程之间控制-基础样例】 1、前言2、环境3、事项了解(1)了解sem概念-了解官网消息(2)根据自己理解,设计几个使用方式(3)不建议运行…...
使用nodejs输出著作权申请所需的word版源码
使用nodejs输出著作权申请所需的word版源码 背景 软件著作权申请需要提供一份80页的word版源代码,如果手工复制源码到word文档中,工作量将无聊到让任何一个DAO人员血压爆表,因此我们不得不编写一个简单的文本处理代码,通过自动方…...
[Vite]vite-plugin-react和vite-plugin-react-swc插件原理了解
[Vite]vite-plugin-react和vite-plugin-react-swc插件原理了解 共同的作用 JSX 支持:插件为 React 应用程序中的 JSX 语法提供支持,确保它可以被正确地转换为 JavaScript。Fast Refresh:提供热更新功能,当应用程序在开发服务器上…...
记一次使用“try-with-resources“的语法导致的BUG
背景描述 最近使用try-catch的时候遇到了一个问题,背景是这样的:当第一次与数据库建立连接以后执行查询完毕并没有手动关闭连接,但是当我第二次获取连接的时候报错了,显示数据库连接失败,连接已经关闭。 org.postgres…...
用Excel处理数据图像,出现交叉怎么办?
一、问题描述 用excel制作X-Y散点图,意外的出现了4个交叉点,而实际上的图表数据是没有交叉的。 二、模拟图表 模拟部分数据,并创建X-Y散点图,数据区域,X轴数据是依次增加的,因此散点图应该是没有交叉的。…...
SpringBoot | 大新闻项目后端(redis优化登录)
该项目的前篇内容的使用jwt令牌实现登录认证,使用Md5加密实现注册,在上一篇:http://t.csdnimg.cn/vn3rB 该篇主要内容:redis优化登录和ThreadLocal提供线程局部变量,以及该大新闻项目的主要代码。 redis优化登录 其实…...
ESP32——物联网小项目汇总
商品级ESP32智能手表 [文章链接] 用ESP32,做了个siri?!开源了! [文章链接]...
flutter:监听路由的变化
问题 当从路由B页面返回路由A页面后,A页面需要进行数据刷新。因此需要监听路由变化 解决 使用RouteObserver进行录音监听 创建全局变量,不在任何类中 final RouteObserver<PageRoute> routeObserver RouteObserver<PageRoute>();在mai…...
Linux多进程和多线程(六)进程间通信-共享内存
多进程(六) 共享内存共享内存的创建 示例: 共享内存删除 共享内存映射 共享内存映射的创建解除共享内存映射示例:写入和读取共享内存中的数据 写入: ### 读取: 大致操作流程: 多进程(六) 共享内存 共享内存是将分配的物理空间直接映射到进程的⽤户虚拟地址空间中, 减少数据在…...
ruoyi后台修改
一、日志文件过大分包 \ruoyi-admin\src\main\resources\logback.xml <!-- 系统日志输出 --> <appender name"file_info" class"ch.qos.logback.core.rolling.RollingFileAppender"><file>${log.path}/sys-info.log</file><!…...
macOS查看系统日志的方法
1、command空格键打开搜索框,输入‘控制台’并打开 2、选择日志报告,根据日期打开自己需要的文件就可以...
数字信号处理及MATLAB仿真(3)——采样与量化
今天写主要来编的程序就是咱们AD变换的两个步骤。一个是采样,还有一个是量化。大家可以先看看,这一过程当中的信号是如何变化的。信号的变换图如下。 先说说采样,采样是将连续时间信号转换为离散时间信号的过程。在采样过程中,连续…...
云端AI大模型群体智慧后台架构思考
1 大模型的调研 1.1 主流的大模型 openai-chatgpt 阿里巴巴-通义千问 一个专门响应人类指令的大模型。我是效率助手,也是点子生成机,我服务于人类,致力于让生活更美好。 百度-文心一言(千帆大模型) 文心一言"…...
算法系列--分治排序|再谈快速排序|快速排序的优化|快速选择算法
前言:本文就前期学习快速排序算法的一些疑惑点进行详细解答,并且给出基础快速排序算法的优化版本 一.再谈快速排序 快速排序算法的核心是分治思想,分治策略分为以下三步: 分解:将原问题分解为若干相似,规模较小的子问题解决:如果子问题规模较小,直接解决;否则递归解决子问题合…...
强化学习编程实战-1-一个及其简单的强化学习实例(多臂赌博机)
1.1 多臂赌博机 一台拥有K个臂的机器,玩家每次可以摇动K个臂中的一个,摇动后,会吐出数量不等的金币,吐出金币的数量服从一定的概率分布,而且不同臂的概率分布不同。 多臂赌博机的问题是:假设玩家共有N次摇地…...
Golang语法规范和风格指南(一)——简单指南
1. 前引 一个语言的规范的学习是重要的,直接关系到你的代码是否易于维护和理解,同时学习好对应的语言规范可以在前期学习阶段有效规避该语言语法和未知编程风格的冲突。 这里是 Google 提供的规范,有助于大家在开始学习阶段对 Golang 进行一…...
数据机构记录顺序表-笔记1
一、线性表的基本概念 数据元素:线性表中的基本单位,每个元素都是线性表的一部分。 数据项:数据元素的具体值。 存储位置:线性表中的元素在内存中的具体存储位置。 线性表按存储结构可以分为顺序表和链表两大类: 1.1…...
考研必备~总结严蔚敏教授《数据结构》课程的重要知识点及考点
作者主页:知孤云出岫 目录 1. 基本概念1.1 数据结构的定义1.2 抽象数据类型 (ADT) 2. 线性表2.1 顺序表2.2 链表 3. 栈和队列3.1 栈3.2 队列 4. 树和二叉树4.1 树的基本概念4.2 二叉树 5. 图5.1 图的基本概念5.2 图的遍历 6. 查找和排序6.1 查找6.2 排序 7. 重点考…...
【数据分享】国家级旅游休闲街区数据(Excel/Shp格式/免费获取)
之前我们分享过从我国文化和旅游部官网整理的2018-2023年我国50个重点旅游城市星级饭店季度经营状况数据(可查看之前的文章获悉详情)!文化和旅游部官网上也分享有很多与旅游相关的常用数据,我们基于官网发布的名单文件整理得到全国…...
Linux开发:进程间通过Unix Domain Socket传递数据
进程间传递数据的方式有很多种,Linux还提供一种特殊的Socket用于在多进程间传递数据,就是Unix Domain Socket(UDS)。 虽然通过普通的Socket也能做到在多进程间传递数据,不过这样需要通过协议栈层的打包与拆包,未免有些浪费效率,通过UDS,数据仅仅通过一个特殊的sock文件…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...
