首页 > 其他分享 >FreeRTOS同步互斥与通信(有缺陷的同步示例,有缺陷的互斥示例)

FreeRTOS同步互斥与通信(有缺陷的同步示例,有缺陷的互斥示例)

时间:2024-10-27 21:18:10浏览次数:8  
标签:同步 示例 int bCanUse 互斥 LCD 线程 缺陷

同步互斥

1. 同步

同步指的是协调多个线程或进程的执行顺序,以确保某些操作按预期的顺序进行。同步主要用于解决依赖关系的问题,确保线程之间的协调。

  • 目的: 保证操作的顺序,确保某些条件成立前不进行后续操作。
  • 实现方式:
    • 信号量: 控制访问共享资源的数量,可以限制同时访问的线程数。
    • 条件变量: 允许线程在某个条件满足之前等待,适用于生产者-消费者问题。
    • 屏障: 让一组线程在某个点上同步,确保所有线程在继续之前都到达该点。

2. 互斥

互斥(Mutual Exclusion)指的是在同一时间只允许一个线程或进程访问某个共享资源,以避免数据冲突或损坏。

  • 目的: 确保在任何时刻只有一个线程可以访问共享资源,保护数据的完整性。
  • 实现方式:
    • 互斥锁(Mutex): 一种简单的锁机制,当一个线程获得锁时,其他线程必须等待,直到锁被释放。
    • 读写锁: 允许多个线程同时读,但在写时只允许一个线程写,适合读多写少的场景。
    • 自旋锁: 在获取锁时,如果锁不可用,线程会忙等待,适用于短时间的锁争用。

总结

  • 同步主要关注操作的顺序和条件,确保各线程按预期顺序执行。
  • 互斥关注资源的独占访问,确保同一时间只有一个线程可以操作共享资源。

这两者结合使用,可以有效地管理多线程环境中的资源访问和执行顺序,从而提高程序的稳定性和性能。

一句话理解同步与互斥:我等你用完厕所,我再用厕所。 什么叫同步?就是:哎哎哎,我正在用厕所,你等会。 什么叫互斥?就是:哎哎哎,我正在用厕所,你不能进来。 同步与互斥经常放在一起讲,是因为它们之的关系很大, “ 互斥 ” 操作可以使用 “ 同步 ” 来 实现。我 “ 等 ” 你用完厕所,我再用厕所。这不就是用 “ 同步 ” 来实现 “ 互斥 ” 吗? 再举一个例子。在团队活动里,同事 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 再用

有缺陷的同步示例

A任务

struct TaskPrintInfo {
	uint8_t x;
	uint8_t y;
	char name[16];
};

static struct TaskPrintInfo g_Task1Info = {0, 0, "Task1"};
static struct TaskPrintInfo g_Task2Info = {0, 3, "Task2"};
static struct TaskPrintInfo g_Task3Info = {0, 6, "Task3"};
static int g_LCDCanUse = 1;
static volatile int g_calc_end=0;
static int g_time = 0;
static int g_sum = 0;

void CalcTask(void *params){
	uint32_t i=0;
	g_time=system_get_ns();
	for(i=0;i<10000000;i++){
		g_sum+=i;
	}
	g_calc_end=1;
	g_time=system_get_ns()-g_time;
	vTaskDelete(NULL);
}

B任务

void LcdPrintTask(void *params)
{
	int len;
	while (1)
	{
		LCD_PrintString(0,0,"Waiting");
		vTaskDelay(3000); 
		while(g_calc_end==0){
		}
		/* ´òÓ¡ÐÅÏ¢ */
		if (g_LCDCanUse)
		{
			g_LCDCanUse = 0;
			LCD_ClearLine(0,0);
			len = LCD_PrintString(0, 0,"Sum:");
			LCD_PrintHex(len, 0, g_sum,1 );
			
			LCD_ClearLine(0,2);
			len=LCD_PrintString(0,2,"Time(ns)");
			LCD_PrintSignedVal(len,2,g_time/1000000);
			g_LCDCanUse = 1;
		}
		vTaskDelete(NULL);
		
	}
}

这样就可以实现同步的任务运行

有缺陷的互斥示例

错误的解决

第一个错误方法思路

在裸机程序里,可以使用一个全局变量或静态变量实现互斥操作,比如要互斥地使用 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。 其中static是所有访问这个函数的任务都可以使用的,但是以上进入Tick中断的情况是发生在04.1与04.2之间那么bCanUse的值已经传入寄存器R0 所以这才可以保证任务同时开启

目前优解(但是没有解决资源浪费的问题)

这是通过关闭中断,来解决不知何时进入中断所导致的互斥问题

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;
}

标签:同步,示例,int,bCanUse,互斥,LCD,线程,缺陷
From: https://blog.csdn.net/2302_79504723/article/details/143243819

相关文章

  • Ruby 和 Python 相比有什么优势和缺陷
    摘要:Ruby与Python相比,在语法灵活性、元编程能力和社区文化方面具有优势;而在科学计算、教育资源和执行效率方面存在不足。在多语言编程环境中,Ruby与Python各有所长。Ruby以其流畅的语法和深入的元编程能力受到部分开发者青睐,这使得Ruby在Web开发、尤其是使用RubyonRAIls......
  • 线程同步(互斥锁条件变量)
     线程同步互斥锁(互斥量)条件变量生产/消费者模型一、互斥锁C++11提供了四种互斥锁:mutex:互斥锁。timed_mutex:带超时机制的互斥锁。recursive_mutex:递归互斥锁。recursive_timed_mutex:带超时机制的递归互斥锁。包含头文件:#include<mutex>1、mutex类1)加锁lock()互斥锁......
  • 04. 微服务 - 示例搭建 - LoadBalancer(一)
    前言基于Eureka示例搭建时的代码hosts增加域名dingsu-300两种设备服务提供者(软交换-sip、300)各两个节点,用于测试负载路由情况负载均衡概念依据各项指标(可使用硬件资源、节点数、请求速率、业务场景等)进行权重考量,将负载(访问请求、工作任务等)分摊到多个服务节点上,从而......
  • C#线程详解及应用示例
     简介在编写应用程序实现业务功能过程中,为解决吞吐量和响应效率的问题,我们会用到多线程、异步编程两项重要的技术。通过它们来提高应用程序响应和高效。应用程序每次运行都会启动一个进程(进程是一种正在执行的程序),而进程中可以包含一个或多个线程,由应用程序入口直接或间接执......
  • sed 命令详解及示例
    sed是一种流编辑器,能高效地完成各种替换、删除、插入等操作,按照文件数据行顺序,重复处理满足条件的每一行数据,然后把结果展示打印,且不会改变原文件内容。sed会逐行扫描输入的数据,并将读取的数据内容复制到临时缓冲区中,称为“模式空间”(patternspace),然后拿模式空间中的数据与给......
  • 【信奥赛·算法基础】CSP-J C++ 贪心算法示例汇总
    序言为了更清晰的了解贪心算法,我把常见的贪心算法示例做了一个总结,把问题和策略,以及代码示例放到了一起,方便学习和分析,这里示例仅以C++为例,其他语言可根据示例调整即可一、钱币找零问题问题描述:给定不同面额的钱币以及每种面额的数量,用最少的钱币张数凑齐给定的总金额。......
  • 缺陷的判定与提交
    第九章提交缺陷报告一、 软件缺陷的判定什么是缺陷软件存在着不符合质量需求或违背软件用户、客户、企业意愿的问题,这就是软件缺陷(Defect),又叫“Bug(臭虫)”。软件缺陷的判定准则软件未达到产品说明书标明的功能;产品说明书简称为说明(spec)或产品说明(productspec),是软件开发小组的一个......
  • 低功耗4G模组:FTP应用示例
    ​一、FTP概述FTP(FileTransferProtocol,文件传输协议)是TCP/IP协议组中的协议之一。FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。其中FTP服务器用来存储文件,用户可以使用FTP客户端通过FTP协议访问位于FTP服务器上的资源。在开发网站的时候,通常利用FTP协议......
  • 将软件集成到 Windows 映像中并进行静默安装,可以使用 DISM 和适当的安装程序命令。下
    将软件集成到Windows映像中并进行静默安装,可以使用DISM和适当的安装程序命令。下面是具体的步骤和示例命令。1.准备工作确保你有一个已挂载的Windows映像。确保你有软件的安装程序,并且支持静默安装。2.挂载映像首先,挂载你的WIM文件(如果还没有挂载的话):bashCopyC......
  • 搭建YOLOv8实现裂缝缺陷识别全流程教程:从源码下载到模型测试
    教程目的:yolov8的安装配置到训练模型,并完成使用模型进行识别前提注意:yolov8要求Python需要版本必需大于等于3.10,我用的Python3.12.3,这里分享下Python3.12.3的安装器=>夸克网盘分享以及教程中用到的yolov8源码、权重文件、GPU配套版本的Torch=> 夸克网盘分享大致步骤1.......