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

RT-Thread 线程间同步

线程间同步

在多线程实时系统中,一项工作的完成往往可以通过多个线程协调的方式共同来完成,那么多个线程之间如何 “默契” 协作才能使这项工作无差错执行?下面举个例子说明。

例如一项工作中的两个线程:一个线程从传感器中接收数据并且将数据写到共享内存中,同时另一个线程周期性的从共享内存中读取数据并发送去显示,下图描述了两个线程间的数据传递:

在这里插入图片描述
如果对共享内存的访问不是排他性的,那么各个线程间可能同时访问它,这将引起数据一致性的问题。

例如,在显示线程试图显示数据之前,接收线程还未完成数据的写入,那么显示将包含不同时间采样的数据,造成显示数据的错乱。

将传感器数据写入到共享内存块的接收线程 #1 和将传感器数据从共享内存块中读出的线程 #2 都会访问同一块内存。为了防止出现数据的差错,两个线程访问的动作必须是互斥进行的,一个线程对共享内存块操作完成后,才允许另一个线程去操作。

同步是指按预定的先后次序进行运行,线程同步是指多个线程通过特定的机制(如互斥量,事件对象,临界区)来控制线程之间的执行顺序,也可以说是在线程之间通过同步建立起执行顺序的关系,如果没有同步,那线程之间将是无序的。

多个线程操作/访问同一块区域(代码),这块代码就称为临界区,上述例子中的共享内存块就是临界区。
线程互斥是指对于临界区资源访问的排他性

当多个线程都要使用临界区资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步。

线程的同步方式有很多种,其核心思想都是:在访问临界区的时候只允许一个 (或一类) 线程运行。

进入 / 退出临界区的方式有很多种:

  1. 调用rt_hw_interrupt_disable()进入临界区,调用rt_hw_interrupt_enable()退出临界区。
  2. 调用rt_enter_critical()进入临界区,调用rt_exit_critical()退出临界区。

信号量

  1. 当停车场空的时候,停车场的管理员发现有很多空车位,此时会让外面的车陆续进入停车场获得停车位;
  2. 当停车场的车位满的时候,管理员发现已经没有空车位,将禁止外面的车进入停车场,车辆在外排队等候;
  3. 当停车场内有车离开时,管理员发现有空的车位让出,允许外面的车进入停车场;待空车位填满后,又禁止外部车辆进入。

管理员就相当于信号量,管理员手中空车位的个数就是信号量的值(非负数,动态变化);停车位相当于公共资源(临界区),车辆相当于线程。车辆通过获得管理员的允许取得停车位,就类似于线程通过获得信号量访问公共资源。

信号量工作机制

信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取或释放它,从而达到同步或互斥的目的。

在这里插入图片描述
每个信号量对象都有一个信号量值和一个线程等待队列,信号量的值对应了资源的实例数目。则表示共有 5 个信号量实例(资源)可以被使用,当信号量实例数目为零时,再申请该信号量的线程就会被挂起在该信号量的等待队列上,等待可用的信号量实例(资源)。

在 RT-Thread 中,信号量控制块是操作系统用于管理信号量的一个数据结构,由结构体 struct rt_semaphore 表示。另外一种 C 表达方式 rt_sem_t,表示的是信号量的句柄,在 C 语言中的实现是指向信号量控制块的指针。信号量控制块结构的详细定义如下:

struct rt_semaphore
{struct rt_ipc_object parent;  /* 继承自 ipc_object 类 */rt_uint16_t value;            /* 信号量的值 */
};
/* rt_sem_t 是指向 semaphore 结构体的指针类型 */
typedef struct rt_semaphore* rt_sem_t;

RT_IPC_FLAG_FIFO 属于非实时调度方式,除非应用程序非常在意先来后到,并且你清楚地明白所有涉及到该信号量的线程都将会变为非实时线程,方可使用 RT_IPC_FLAG_FIFO,否则建议采用 RT_IPC_FLAG_PRIO,即确保线程的实时性。

若删除信号量时,有线程正在等待信号量,那么删除操作会先唤醒该线程(等待线程的返回值是 - RT_ERROR),然后再释放信号量的内存资源。

对于静态信号量对象,它的内存空间在编译时期就被编译器分配出来,放在读写数据段或未初始化数据段上,只需要在使用前对它进行初始化即可。

信号量应用示例

这是一个信号量使用例程,该例程创建了一个动态信号量,初始化两个线程,一个线程发送信号量,一个线程接收到信号量后,执行相应的操作。

#include <rtthread.h>#define THREAD_PRIORITY         25
#define THREAD_TIMESLICE        5/* 指向信号量的指针 */
static rt_sem_t dynamic_sem = RT_NULL;ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread1;
static void rt_thread1_entry(void *parameter)
{static rt_uint8_t count = 0;while(1){if(count <= 100){count++;}elsereturn;/* count 每计数 10 次,就释放一次信号量 */if(0 == (count % 10)){rt_kprintf("t1 release a dynamic semaphore.\n");rt_sem_release(dynamic_sem);}}
}ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
static void rt_thread2_entry(void *parameter)
{static rt_err_t result;static rt_uint8_t number = 0;while(1){/* 永久方式等待信号量,获取到信号量,则执行 number 自加的操作 */result = rt_sem_take(dynamic_sem, RT_WAITING_FOREVER);if (result != RT_EOK){rt_kprintf("t2 take a dynamic semaphore, failed.\n");rt_sem_delete(dynamic_sem);return;}else{number++;rt_kprintf("t2 take a dynamic semaphore. number = %d\n" ,number);}}
}/* 信号量示例的初始化 */
int semaphore_sample(void)
{/* 创建一个动态信号量,初始值是 0 */dynamic_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_PRIO);if (dynamic_sem == RT_NULL){rt_kprintf("create dynamic semaphore failed.\n");return -1;}else{rt_kprintf("create done. dynamic semaphore value = 0.\n");}rt_thread_init(&thread1,"thread1",rt_thread1_entry,RT_NULL,&thread1_stack[0],sizeof(thread1_stack),THREAD_PRIORITY, THREAD_TIMESLICE);rt_thread_startup(&thread1);rt_thread_init(&thread2,"thread2",rt_thread2_entry,RT_NULL,&thread2_stack[0],sizeof(thread2_stack),THREAD_PRIORITY-1, THREAD_TIMESLICE);rt_thread_startup(&thread2);return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(semaphore_sample, semaphore sample);

相关文章:

RT-Thread 线程间同步

线程间同步 在多线程实时系统中&#xff0c;一项工作的完成往往可以通过多个线程协调的方式共同来完成&#xff0c;那么多个线程之间如何 “默契” 协作才能使这项工作无差错执行&#xff1f;下面举个例子说明。 例如一项工作中的两个线程&#xff1a;一个线程从传感器中接收…...

Python元类再解释

Python元类再解释 元类是什么&#xff1f; 你可以把元类看作是“生产类的工厂”。就像类是用来生产对象的&#xff0c;元类是用来生产类的。 为什么需要元类&#xff1f; 考虑一个场景&#xff1a;假设你正在编写一个框架&#xff0c;你希望框架中的所有类都有某些特定的方…...

常用的Spring Boot 注解及示例代码

简介&#xff1a;Spring Boot 是一个用于快速构建基于 Spring 框架的应用程序的工具&#xff0c;通过提供一系列的注解&#xff0c;它使得开发者可以更加轻松地配置、管理和控制应用程序的各种行为。以下是一些常用的 Spring Boot 注解&#xff0c;以及它们的功能和示例代码&am…...

react app教程

react app教程 环境准备 下载node 下载npx npm install npx创建app npx create-react-app automedia cd automedia npm start构建发布版本 npm run build安装调试工具 # .vscode/launch.json {// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了…...

在vue项目中用vue-watermark快捷开发屏幕水印效果

我们先引入一个第三方依赖 npm install vue-watermark然后 因为这只是个测试工具 我就直接代码写 App.vue里啦 参考代码如下 <template><div><vue-watermark :text"watermarkText"></vue-watermark><!-- 正常的页面内容 --></div…...

无涯教程-Android - Activity

Activity代表具有用户界面的单个屏幕&#xff0c;就像Java的窗口或框架一样。Android Activity 是ContextThemeWrapper类的子类。 如果您使用过C&#xff0c;C或Java编程语言&#xff0c;那么您一定已经看到您的程序从 main()函数开始。与之非常相似&#xff0c;Android系统以 …...

vue项目前端展示数学公式(在表格中渲染)

现有需求为 将实验数据录入表格中,需要表格呈现物理公式,使用Mathjax在vue2中 进行呈现 1.安装 npm i --save mathjax-vue 2.全局注册(main.js中) import MathJax, { initMathJax, renderByMathjax } from mathjax-vuefunction onMathJaxReady() {const el document.getEl…...

java八股文面试[数据库]——MySQL索引的数据结构

知识点&#xff1a; 【2023年面试】mysql索引的基本原理_哔哩哔哩_bilibili 【2023年面试】mysql索引结构有哪些&#xff0c;各自的优劣是什么_哔哩哔哩_bilibili...

python3.11教程2:基础数据类型(数字和字符串)、组合数据类型(集合、元组、列表、字典)

文章目录 五、基本数据类型5.1 整数和浮点数5.1.1 整数和浮点数的类型5.1.2 进制和进制转换5.1.3 round函数 5.2 运算符5.2.1 常用运算符、运算符函数和逻辑运算符5.2.2 位运算符5.2.3 运算符的优先级及其进阶使用 5.3 布尔类型5.4 字符串5.3.1 字符串的基本操作5.3.2 字符串函…...

剑指 Offer 44. 数字序列中某一位的数字(中等)

题目&#xff1a; class Solution { //本题单纯找规律&#xff0c;要注意通过n%digits来判断有几个位数为digits的数 public:int findNthDigit(int n) {long base 9, digits 1; //digits代表位数while(n-base*digits>0){ //该循环是为了确定目标数字所在…...

SpringBoot中HttpClient的学习

一、介绍 HttpClient是Apache Jakarta Common 下的子项目&#xff0c;可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包。 HttpClient 是一个HTTP通信库、一个工具包&#xff0c;它只提供一个通用浏览器应用程序所期望的功能子集&#xff0c;与浏览…...

JVM-内存溢出的原因、CPU占满的原因

1.内存溢出的原因 OOM的排查思路_oom排查_java排坑日记的博客-CSDN博客 每个进程的内存&#xff08;限制&#xff0c;譬如2G&#xff09;最大堆容量最大方法区容量程序计数器虚拟机栈和本地方法栈。多线程下每个线程栈越大&#xff0c;越容易OOM. 1.堆内存溢出&#xff08;OO…...

如何做好银行统一报送系统UI设计

北京蓝蓝设计公司是一支由清华美院毕业的专业团队组成的设计公司。我们的设计师们在金融银行软件领域拥有12年的工作经验和丰富的行业知识。 在工作中我们常常思考银行金融反洗钱软件用户使用痛点是什么&#xff1f;我们发现用户的使用痛点往往是&#xff1a; 1功能入口不清晰…...

988. 从叶结点开始的最小字符串

988. 从叶结点开始的最小字符串 C代码&#xff1a;DFS /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/// 叶子节点// 每一层用一个pathTop、遇到叶子节点就判断一次&#xff1b;…...

RealSense D455启动教程

环境&#xff1a; ubuntu20.04 ros:noetic 视觉传感器&#xff1a;Intel RealSense D455 通过命令安装不成功后改为下面源码安装 1. 安装Intel RealSense SDK 2.0 1.1源码安装 1. 下载源码git clone https://github.com/IntelRealSense/librealsense cd librealsense…...

docker与phpstudy两种方式部署wordpress 并 开启伪静态

实际测试&#xff0c;可能是docker内存限制的缘故&#xff0c;docker部署的会比较卡 下载 wordpress phpstudy phpstudy中伪静态配置 伪静态 正常访问 WordPress 文章页的 URL 地址为 http://asa/index.php?p123。变成伪静态就是http://asa/123.html 。 伪静态是相对真实静…...

网站搭建最简化的引导操作 | 云服务器的购买选用 | 域名的选用 | 网站的上线和备案。

本文章面向对象为网站搭建的初次操作者&#xff0c;主要是一些自主使用的网站&#xff0c;为小白做为引导的教程。 一&#xff0c; 网站搭建的流程 1&#xff0c;服务器的租赁 2&#xff0c;购买域名 3&#xff0c;对域名进行备案 4&#xff0c;网站内部的搭建&#xff0c;上线…...

Spring Cloud Foundry上使用通配符模式匹配进行的安全绕过漏洞 CVE-2023-20873

文章目录 0.前言1.参考文档2.基础介绍描述如果满足以下任一条件&#xff0c;应用程序就不会有太大风险&#xff1a;受影响的Spring产品和版本 3.解决方案3.1. 升级版本3.2. 替代方案 0.前言 背景&#xff1a;公司项目扫描到 Spring Cloud Foundry上使用通配符模式匹配进行的安全…...

简述SpringMVC

一、典型的Servlet JSP JavaBean UserServlet看作业务逻辑处理&#xff08;Controller&#xff09;User看作模型&#xff08;Model&#xff09;user.jsp看作渲染&#xff08;View&#xff09; 二、高级MVC 由DispatcherServlet对请求统一处理 三、SpringMVC MVC与Spr…...

vue竖向步骤条

效果图&#xff1a; 弹框组件代码&#xff1a; <template><el-dialog:visible.sync"dialogVisible":append-to-body"true":close-on-click-modal"false":close-on-press-escape"false"titlewidth"8.2rem"custom-c…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...