当前位置: 首页 > news >正文

【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)
{// 创建一个信号量,初始值为 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、总结

一个砖一个砖,垒起来。

http://www.lryc.cn/news/393241.html

相关文章:

  • 使用nodejs输出著作权申请所需的word版源码
  • [Vite]vite-plugin-react和vite-plugin-react-swc插件原理了解
  • 记一次使用“try-with-resources“的语法导致的BUG
  • 用Excel处理数据图像,出现交叉怎么办?
  • SpringBoot | 大新闻项目后端(redis优化登录)
  • ESP32——物联网小项目汇总
  • flutter:监听路由的变化
  • Linux多进程和多线程(六)进程间通信-共享内存
  • ruoyi后台修改
  • macOS查看系统日志的方法
  • 数字信号处理及MATLAB仿真(3)——采样与量化
  • 云端AI大模型群体智慧后台架构思考
  • 算法系列--分治排序|再谈快速排序|快速排序的优化|快速选择算法
  • 强化学习编程实战-1-一个及其简单的强化学习实例(多臂赌博机)
  • Golang语法规范和风格指南(一)——简单指南
  • 数据机构记录顺序表-笔记1
  • 考研必备~总结严蔚敏教授《数据结构》课程的重要知识点及考点
  • 【数据分享】国家级旅游休闲街区数据(Excel/Shp格式/免费获取)
  • Linux开发:进程间通过Unix Domain Socket传递数据
  • Redis基础教程(九):redis有序集合
  • Servlet与Servlet容器
  • 腾讯centos mysql安装
  • c_各个unsigned int 和 int的取值范围
  • C#/WPF 自制截图工具
  • 以腾讯为例,手把手教你搭建产品帮助中心
  • 计算机网络概述--自我学习用
  • 超级好用的java http请求工具
  • 在原有的iconfont.css文件中加入新的字体图标
  • 使用 ESP32-WROOM + DHT11 做个无屏温湿度计
  • 如何使用 SwiftUI 构建 visionOS 应用