第10章_freeRTOS入门与工程实践之同步互斥与通信

news2024/9/21 0:40:48

本教程基于韦东山百问网出的 DShanMCU-F103开发板 进行编写,需要的同学可以在这里获取: https://item.taobao.com/item.htm?id=724601559592

配套资料获取:https://rtos.100ask.net/zh/freeRTOS/DShanMCU-F103

freeRTOS系列教程之freeRTOS入门与工程实践章节汇总: https://blog.csdn.net/qq_35181236/article/details/132842016


第10章 同步互斥与通信

本章是概述性的内容。可以把多任务系统当做一个团队,里面的每一个任务就相当于团队里的一个人。团队成员之间要协调工作进度(同步)、争用会议室(互斥)、沟通(通信)。多任务系统中所涉及的概念,都可以在现实生活中找到例子。

各类RTOS都会涉及这些概念:任务通知(task notification)、队列(queue)、事件组(event group)、信号量(semaphoe)、互斥量(mutex)等。我们先站在更高角度来讲解这些概念。

10.1 同步与互斥的概念

一句话理解同步与互斥:我等你用完厕所,我再用厕所。

什么叫同步?就是:哎哎哎,我正在用厕所,你等会。
什么叫互斥?就是:哎哎哎,我正在用厕所,你不能进来。

同步与互斥经常放在一起讲,是因为它们之的关系很大,“互斥”操作可以使用“同步”来实现。我“等”你用完厕所,我再用厕所。这不就是用“同步”来实现“互斥”吗?

再举一个例子。在团队活动里,同事A先写完报表,经理B才能拿去向领导汇报。经理B必须等同事A完成报表,AB之间有依赖,B必须放慢脚步,被称为同步。在团队活动中,同事A已经使用会议室了,经理B也想使用,即使经理B是领导,他也得等着,这就叫互斥。经理B跟同事A说:你用完会议室就提醒我。这就是使用"同步"来实现"互斥"。

有时候看代码更容易理解,伪代码如下:

 void  抢厕所(void)
 {
   if (有人在用) 我眯一会;
   用厕所;
   喂,醒醒,有人要用厕所吗;
 }

假设有A、B两人早起抢厕所,A先行一步占用了;B慢了一步,于是就眯一会;当A用完后叫醒B,B也就愉快地上厕所了。

在这个过程中,A、B是互斥地访问“厕所”,“厕所”被称之为临界资源。我们使用了“休眠-唤醒”的同步机制实现了“临界资源”的“互斥访问”。

同一时间只能有一个人使用的资源,被称为临界资源。比如任务A、B都要使用串口来打印,串口就是临界资源。如果A、B同时使用串口,那么打印出来的信息就是A、B混杂,无法分辨。所以使用串口时,应该是这样:A用完,B再用;B用完,A再用。

10.2 同步与互斥并不简单

在裸机程序里,可以使用一个全局变量或静态变量实现互斥操作,比如要互斥地使用LCD,可以使用如下代码:

 int LCD_PrintString(int x, int y, char *str) 
 {
   static int bCanUse = 1;
   if (bCanUse)
   { 
     bCanUse = 0;
     /* 使用LCD */
     bCanUse = 1;
     return 0;
   }
   return -1;
 }

但是在RTOS里,使用上述代码实现互斥操作时,大概率是没问题的,但是无法确保万无一失。

假设如下场景:有两个任务A、B都想调用LCD_PrintString,任务A执行到第4行代码时发现bCanUse为1,可以进入if语句块,它还没执行第6句指令就被切换出去了;然后任务B也调用LCD_PrintString,任务B执行到第4行代码时也发现bCanUse为1,也可以进入if语句块使用LCD。在这种情况下,使用静态变量并不能实现互斥操作。

上述例子中,是因为第4、第6两条指令被打断了,那么如下改进:在函数入口处先然让bCanUse减一。这能否实现万无一失的互斥操作呢?

 int LCD_PrintString(int x, int y, char *str) 
 {
   static int bCanUse = 1;
   bCanUse--;
   if (bCanUse == 0)
   { 
     /* 使用LCD */
     bCanUse++;
     return 0;
   }
   else
   {
     bCanUse++;
     return -1;
   }
 }

把第4行的代码使用汇编指令表示如下:

04.1 LDR R0, [bCanUse]  	// 读取bCanUse的值,存入寄存器R0

04.2 DEC R0, #1     	    // 把R0的值减一

04.3 STR R0, [bCanUse]      // 把R0写入变量bCanUse 

假设如下场景:有两个任务A、B都想调用LCD_PrintString,任务A执行到第04.1行代码时读到的bCanUse为1,存入寄存器R0就被切换出去了;然后任务B也调用LCD_PrintString,任务B执行到第4行时发现bCanUse为1并把它减为0,执行到第5行代码时发现条件成立可以进入if语句块使用LCD,然后任务B也被切换出去了;现在任务A继续运行第04.2行代码时R0为1,运行到第04.3行代码时把bCanUse设置为0,后续也能成功进入if的语句块。在这种情况下,任务A、B都能使用LCD。

上述方法不能保证万无一失的原因在于:在判断过程中,被打断了。如果能保证这个过程不被打断,就可以了:通过关闭中断来实现。

示例1的代码改进如下:在第5~7行前关闭中断。

 int LCD_PrintString(int x, int y, char *str) 
 {
   static int bCanUse = 1;
   disable_irq();
   if (bCanUse)
   { 
        bCanUse = 0;
        enable_irq();
       /* 使用LCD */
        bCanUse = 1;
        return 0;
   }
   enable_irq();
   return -1;
 }

示例2的代码改进如下:在第5行前关闭中断。

 int LCD_PrintString(int x, int y, char *str) 
 {
   static int bCanUse = 1;
   disable_irq();
   bCanUse--;
   enable_irq();
   if (bCanUse == 0)
   { 
     /* 使用LCD */
     bCanUse++;
     return 0;
   }
   else
   {
     disable_irq();
     bCanUse++;
     enable_irq();
     return -1;
   }
 }

10.3 各类方法的对比

能实现同步、互斥的内核方法有:任务通知(task notification)、队列(queue)、事件组(event group)、信号量(semaphoe)、互斥量(mutex)。

它们都有类似的操作方法:获取/释放、阻塞/唤醒、超时。比如:

  • 任务A获取资源,用完后任务A释放资源
  • 任务A获取不到资源则阻塞,任务B释放资源并把任务A唤醒
  • 任务A获取不到资源则阻塞,并定个闹钟;A要么超时返回,要么在这段时间内因为任务B释放资源而被唤醒。

这些内核对象五花八门,记不住怎么办?我也记不住,通过对比的方法来区分它们。

  • 能否传信息?还是只能传递状态?
  • 为众生(所有任务都可以使用)?只为你(只能指定任务使用)?
  • 我生产,你们消费?
  • 我上锁,只能由我开锁
内核对象生产者消费者数据/状态说明
队列ALLALL数据:若干个数据 谁都可以往队列里扔数据, 谁都可以从队列里读数据用来传递数据, 发送者、接收者无限制, 一个数据只能唤醒一个接收者
事件组ALLALL多个位:或、与 谁都可以设置(生产)多个位, 谁都可以等待某个位、若干个位用来传递事件, 可以是N个事件, 发送者、接受者无限制, 可以唤醒多个接收者:像广播
信号量ALLALL数量:0~n 谁都可以增加一个数量, 谁都可消耗一个数量用来维持资源的个数, 生产者、消费者无限制, 1个资源只能唤醒1个接收者
任务通知ALL只有我数据、状态都可以传输, 使用任务通知时, 必须指定接受者N对1的关系: 发送者无限制, 接收者只能是这个任务
互斥量只能A开锁A上锁位:0、1 我上锁:1变为0, 只能由我开锁:0变为1就像一个空厕所, 谁使用谁上锁, 也只能由他开锁

使用图形对比如下:

  • 队列:

    • 里面可以放任意数据,可以放多个数据
    • 任务、ISR都可以放入数据;任务、ISR都可以从中读出数据
  • 事件组:

    • 一个事件用一bit表示,1表示事件发生了,0表示事件没发生
    • 可以用来表示事件、事件的组合发生了,不能传递数据
    • 有广播效果:事件或事件的组合发生了,等待它的多个任务都会被唤醒
  • 信号量:

    • 核心是"计数值"
    • 任务、ISR释放信号量时让计数值加1
    • 任务、ISR获得信号量时,让计数值减1
  • 任务通知:

    • 核心是任务的TCB里的数值
    • 会被覆盖
    • 发通知给谁?必须指定接收任务
    • 只能由接收任务本身获取该通知
  • 互斥量:

    • 数值只有0或1
    • 谁获得互斥量,就必须由谁释放同一个互斥量

10.4 各类方法的本质


本章完

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HBASE知识点

HBASE是什么? 高可靠、高性能、面向列、可伸缩、实时读写的分布式数据库。利用HDFS作为其文件存储系统,利用MapReduce来处理HBase中的海量数据。利用Zookeeper作为其分布式协同服务。用于存储非结构化和半结构化的松散数据。 HBase数据模型 RowKey: 唯…

makefile的编写:由浅入深

文章目录 准备文件Makefile版本一Makefile版本二Makefile版本三Makefile版本四Makefile版本五 准备文件 // fun1.c #include <stdio.h> void fun1() {printf("this is fun1\n"); }// fun2.c #include <stdio.h> void fun2() {printf("this is fun2…

Java面试常用函数

1. charAt() 方法用于返回字符串指定索引处的字符。索引范围为从 0 到 length() - 1。 map.getOrDefault(num, 0) :如果map存在num这个key&#xff0c;则返回num对应的value&#xff0c;否则返回0. Arrays.sort(nums); 数组排序 Arrays.asList("a","b",&q…

SpringMVC中的JSR303与拦截器的使用

一&#xff0c;JSR303的概念 JSR303是Java中的一个标准&#xff0c;用于验证和校验JavaBean对象的属性的合法性。它提供了一组用于定义验证规则的注解&#xff0c;如NotNull、Min、Max等。在Spring MVC中&#xff0c;可以使用JSR303注解对请求参数进行校验。 1.2 为什么要使用J…

2023年墨西哥 SP/BMV IPC 研究报告

第一章 指数概况 1.1 指数基本情况 墨西哥 S&P/BMV IPC 指数衡量在墨西哥证券交易所 (Bolsa Mexicana de Valores, BMV)上市&#xff0c;规模最大、流动性最高的股票表现。提供一个覆盖墨西哥股市的广泛、具有代表性且可轻易复制的指数。根据多元化要求&#xff0c;按市值…

Redis哨兵Cluster群集 搭建

Redis群集 Redis群集有三种模式 主从同步/复制哨兵模式Cluster群集 主从同步/复制 概念 主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份&#xff0c;以及对于读操作的负载均衡和简单的故障恢复缺陷…

ENVI_IDL: 基础语法详解

01 题目 02 代码说明 题目本身很简单&#xff0c;但是我自己加了一些东西进去增加难度。主要包括print函数的封装、格式化字符串&#xff0c;但是不影响代码的阅读。&#xff08;注&#xff1a;对于没有语言基础的人而言相对阅读困难&#xff0c;但是由于IDL是解释型语言&…

文字点选验证码识别(下)-训练一个孪生神经网络模型

声明 本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。 本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。 如有侵权,请联系我进行删除。 文章中没有代码,只有过程思路,请大家谨慎订阅。…

Windows下的Elasticsearch-head安装

Windows下的Elasticsearch-head安装 参考&#xff1a;https://gitcode.net/mirrors/mobz/elasticsearch-head 需要用到 npm 命令&#xff0c;这里可以提前下载安装下Node.js 即可自动安装npm&#xff1b; Node.js 下载安装地址&#xff1a;https://nodejs.org/en/download # 进…

【Unity每日一记】音频,麦克风,粒子和拖尾渲染器

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

LCD1602液晶显示屏介绍和程序开发

1.LCD1602概述 LCD1602&#xff08;Liquid Crystal Display&#xff09;是一种工业字符型液晶&#xff0c;能够同时显示 1602 即 32 字符(16列两行) 引脚说明第 1 脚: VSS 为电源地第 2 脚: VDD 接 5V 正电源第 3 脚: VL 为液晶显示器对比度调整端,接正电源时对比度最弱&…

华为云云耀云服务器L实例评测| ultralytics最先进模型YOLOv8深度学习AI训练

目录 前言 登录服务器 安装pyhton 部署yolov8 安装Pytorch 下载权重文件 训练模型 前言 前几期我们在云耀云服务器L实例上分别使用docker和直接在centos上部署了yolov5识别API&#xff0c;前端项目vue&#xff0c;后端项目.net Core Web Api,但是从监控图上来看&#…

联网汽车和网络犯罪:入门

正在权衡如何投资预算的原始设备供应商 ( OEM ) 及其供应商可能倾向于放慢应对网络威胁的投资。迄今为止&#xff0c;他们遇到的攻击仍然相对简单&#xff0c;危害性也不是特别大。 然而&#xff0c;对地下犯罪信息交换中的聊天记录的分析表明&#xff0c;这些碎片的存在是为了…

html5学习笔记22-JavaScript 简略学习

https://www.runoob.com/js/js-tutorial.html JavaScript 是 Web 的编程语言。与java无关。 案例&#xff1a;https://c.runoob.com/examples/ JavaScript 是一种轻量级的编程语言、可插入 HTML 页面的编程代码、脚本语言。 ECMA-262 是 JavaScript 标准的官方名称。 HTML 中的…

房地产小程序 | 小程序赋能,房地产业务数字化升级

随着科技的不断发展&#xff0c;房地产行业正逐渐向数字化转型。在这个过程中&#xff0c;房地产小程序成为了一种重要的工具&#xff0c;可以帮助房地产企业提供更好的购房体验、增加销售额&#xff0c;并实现管理的便捷化。 优点 便捷购房体验&#xff1a;房地产小程序为用户…

vite + react + typescript + uni-app + node 开发一个生态系统

简介 使用 vite react typescript uni-app node 来开发一个简易的生态系统案例&#xff0c;包含 APP&#xff0c;H5&#xff0c;微信小程序&#xff0c;控制台&#xff0c;服务端 开发 admin 技术栈&#xff1a;vite react typescript初始化控制台项目选择自定义预设…

快速傅里叶变化

引言 目标 傅里叶变化&#xff08;Fourier transform&#xff09;是一种信号处理技术&#xff0c;它可以将时间信号转换为频率信号&#xff0c;即将一组具有相同数量频率的正弦波叠加在一起&#xff0c;形成一组新的正弦波。如果我们把时间信号从频域转换到时域&#xff0c;那么…

手搭手入门MybaitsX

Mybatis-Plus介绍 为简化开发而生 MyBatis-Plus(opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis(opens new window) 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 特性 无侵入&#xff1a;只做增强…

2022年全国研究生数学建模竞赛华为杯C题汽车制造涂装-总装缓存调序区调度优化问题求解全过程文档及程序

2022年全国研究生数学建模竞赛华为杯 C题 汽车制造涂装-总装缓存调序区调度优化问题 原题再现&#xff1a; 背景介绍   汽车制造厂主要由焊装车间、涂装车间、总装车间构成&#xff0c;每个车间有不同的生产偏好&#xff0c;如&#xff1a;焊装车间由于车身夹具的限制偏向最…

【C语言】指针的“最后一站”【进阶版】

欢迎各位看官^_^ 目录 1、字符指针 2、指针数组 3、数组指针 3.1数组指针的定义 3.2数组指针的使用 4、数组指针和指针数组的区别 5、数组参数&#xff0c;指针参数 5.1数组参数定义 5.2指针参数定义 5.3一维数组传参 5.4二维数组传参 5.5一级指针传参 5.6二级指…