基于STM32结合CubeMX学习Free-RT-OS的源码之信号量与互斥量

news2025/7/6 14:48:00

目录

CUBEMX上的配置以及使用

信号量

互斥量


CUBEMX上的配置以及使用

信号量与互斥量都是从队列中衍生出来的,他们是一种特殊的队列。不同的地方在于:他们不含有队列的数据部分,只有队列结构体。 

定义属性(这里只有一个名字)和创建

信号量

 信号量又分二值信号量和计数信号量,本质上都是是资源可用的个数。

二值信号量只有0和1两个值。

二值信号量的创建  ( 参数部分为 队列长度为1(也就是计数值),数据成员类型大小为 0,队列类型为信号量类型)

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )

    #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )

#endif

pxQueue->uxMessagesWaiting     //在队列里现有数据个数,在信号量里则是计数值。

 //二值信号量则这个值只有 0 或 1

数据部分为0然后调用创建队列的哪一套库函数。(初始化了等待发送信号量链表,等待接受信号链接,这和队列里的等待读与等待写是一样的),以及主要的超时阻塞与任务的唤醒也一样。

经过源码发现,FREE RT OS重命名了获取信号量的函数

BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait )

然而  释放信号量还是通过宏调用通用的队列写数据的方法

超时阻塞与任务唤醒参考

基于STM32结合CubeMX学习Free-RT-OS的源码之消息队列_昊月光华的博客-CSDN博客

互斥量

本文主要还是学习互斥量。

为什么?因为它有优先级继承这一特殊的机制防止优先级反转。

在操作系统的日常任务中,有些操作看起来只有一步,但在汇编代码中却有好几步!在抢占式得实时操作系统中,比如有多个任务对同一个值进行写回操作,则必须要求对该值操作时互斥。

为什么要互斥?

任务1: a++;

任务2 :a++

试想进行这两个任务,尽管我的STM32F1是一个只能单核运行的CPU,但是任务是会抢占的,抢占的同时,保留现场,当前任务的变量值入栈。

任务1运行,a++  。(从汇编上看分三步,第一步将内存里a的值取出装载到寄存器,第二步,该寄存器的值自增1,第三步写回)

若在a++执行的第三步写回之前被任务2抢占则会发生:

1:任务1的a的值(未写回)入栈。

2: sp(此时指向psp)指针切换任务2函数入口开始执行a++,由于上一个任务a还没有写回,a++执行并写回a为1。任务2执行完毕再恢复任务1的现场,a的值从栈中取出为0,这时候执行a++则a为1再写回。这样就导致了丢失修改。

这种情况下,如何解决,把a定义成__IO  也就是volatile 能解决这个丢失修改的问题。

volatile是一个特征修饰符(type specifier)。volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。 

简单地说:编译器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份

我们知道,从内存里读取与从寄存器里读取的速度效率是不同的,寄存机效率大于内存。

使用互斥量则可以很好地解决在使用临界资源互斥的问题。

创建互斥量

 

 

递归互斥量与普通互斥量的区别:

  • 递归互斥量可以多次获取锁,并获取多少次锁就必须释放多少次锁。并规定由谁获取锁就又谁解锁。
  • 普通互斥量,只能获取一次锁,可以让不同的任务获取锁和释放锁(易造成死锁局面,最好是成对存在。)

释放和获取调用的是信号量的API,在函数内部对互斥量的情形进行判断。

获取互斥锁

     xSemaphoreTake(USEESPMUTEXHandle,portMAX_DELAY);

 xTaskPriorityInherit                             //优先级继承

 当高优先级的任务获取互斥锁时会干以下事情:

若是能获取锁(队列里的计数值为1)则减1为0。互斥量的队列头部记录当前持有互斥量的任务。

若无法获取锁,且超时阻塞等待获取锁时(把自己放入互斥量的等待读链表中),则进行判断当前获取互斥量的任务的优先级是否大于持有互斥量的任务的优先级,若是,则继承当前任务(高优先级)的优先级,同时再次判断持有互斥量的任务是否就绪,若是则加入被继承的优先级的就绪链表中,防止在两者优先级之间的任务插队。这就是优先级继承,防止了优先级的反转。

当继承了高优先级的低优先级的任务一旦释放了互斥量,若高优先级任务还在等待,则唤醒高优先级的任务,自己则恢复为原来的优先级,并把自己由于继承高优先级所在的高优先级链表移除并移动到原来的优先级链表。(相当于高优先级体验卡体验结束)。

 

BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
	{
	TCB_t * const pxMutexHolderTCB = ( TCB_t * ) pxMutexHolder;
	BaseType_t xReturn = pdFALSE;

		/* If the mutex was given back by an interrupt while the queue was
		locked then the mutex holder might now be NULL.  _RB_ Is this still
		needed as interrupts can no longer use mutexes? */
		if( pxMutexHolder != NULL )
		{
			/* If the holder of the mutex has a priority below the priority of
			the task attempting to obtain the mutex then it will temporarily
			inherit the priority of the task attempting to obtain the mutex. */
			if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority )
			{
				/* Adjust the mutex holder state to account for its new
				priority.  Only reset the event list item value if the value is
				not being used for anything else. */
				if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
				{
					listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}

				/* If the task being modified is in the ready state it will need
				to be moved into a new list. */
				if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE )
				{
					if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
					{
						taskRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority );
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					/* Inherit the priority before being moved into the new list. */
					pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
					prvAddTaskToReadyList( pxMutexHolderTCB );
				}
				else
				{
					/* Just inherit the priority. */
					pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
				}

				traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCB->uxPriority );

				/* Inheritance occurred. */
				xReturn = pdTRUE;
			}
			else
			{
				if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority )
				{
					/* The base priority of the mutex holder is lower than the
					priority of the task attempting to take the mutex, but the
					current priority of the mutex holder is not lower than the
					priority of the task attempting to take the mutex.
					Therefore the mutex holder must have already inherited a
					priority, but inheritance would have occurred if that had
					not been the case. */
					xReturn = pdTRUE;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		return xReturn;
	}

释放互斥锁

   xSemaphoreGive(USEESPMUTEXHandle);

 xTaskPriorityDisinherit                               //优先级取消继承(恢复为原来的优先级)

	BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder )
	{
	TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
	BaseType_t xReturn = pdFALSE;

		if( pxMutexHolder != NULL )
		{
			/* A task can only have an inherited priority if it holds the mutex.
			If the mutex is held by a task then it cannot be given from an
			interrupt, and if a mutex is given by the holding task then it must
			be the running state task. */
			configASSERT( pxTCB == pxCurrentTCB );
			configASSERT( pxTCB->uxMutexesHeld );
			( pxTCB->uxMutexesHeld )--;

			/* Has the holder of the mutex inherited the priority of another
			task? */
			if( pxTCB->uxPriority != pxTCB->uxBasePriority )
			{
				/* Only disinherit if no other mutexes are held. */
				if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 )
				{
					/* A task can only have an inherited priority if it holds
					the mutex.  If the mutex is held by a task then it cannot be
					given from an interrupt, and if a mutex is given by the
					holding task then it must be the running state task.  Remove
					the holding task from the ready list. */
					if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
					{
						taskRESET_READY_PRIORITY( pxTCB->uxPriority );
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					/* Disinherit the priority before adding the task into the
					new	ready list. */
					traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
					pxTCB->uxPriority = pxTCB->uxBasePriority;

					/* Reset the event list item value.  It cannot be in use for
					any other purpose if this task is running, and it must be
					running to give back the mutex. */
					listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
					prvAddTaskToReadyList( pxTCB );

					/* Return true to indicate that a context switch is required.
					This is only actually required in the corner case whereby
					multiple mutexes were held and the mutexes were given back
					in an order different to that in which they were taken.
					If a context switch did not occur when the first mutex was
					returned, even if a task was waiting on it, then a context
					switch should occur when the last mutex is returned whether
					a task is waiting on it or not. */
					xReturn = pdTRUE;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		return xReturn;
	}

在释放互斥锁时判断此任务是否有继承过高优先级的任务, 

if( pxTCB->uxPriority != pxTCB->uxBasePriority )

若是则恢复为原优先级, 并把自己从高优先级的链表中移除,加入到自己原来的优先级链表中。

若是一个高优先级的任务阻塞超时,低优先级的任务继承后,被更高优先级的任务抢占,则高优先级的任务在获取互斥量时判断超时后调用取消优先级继承函数。低优先级的继承体验卡只在高优先级阻塞时有效。

void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask )

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

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

相关文章

Handler 消息队列中的同步屏障——Message

Message 分为3种&#xff1a;普通消息&#xff08;同步消息&#xff09;、屏障消息&#xff08;同步屏障&#xff09;和异步消息。我们通常使用的都是普通消息&#xff0c;而屏障消息就是在消息队列中插入一个屏障&#xff0c;在屏障之后的所有普通消息都会被挡着&#xff0c;不…

隐式类型转换(整形提升)

隐式类型转换1.定义2.整形提升例子3.char的取值范围和一些技巧1.定义 1.c的整形算术运算总是至少以缺省整形类型的精度来进行的。 2.为了获取这个精度&#xff0c;像字符型&#xff0c;短整形在使用之前会转换为整形&#xff0c;这种转换被称为整形提升 3.整形提升时补最高位的…

Baklib|信息管理和知识管理是如何影响你的业务的?

有效的信息和知识管理可以让您消除库和共享知识。本文讨论了信息管理和知识管理的来龙去脉。信息管理和知识管理通常可以互换使用&#xff0c;但也有关键的区别。了解这些差异以及它们如何影响您的业务&#xff0c;可以使您优化管理策略、简化工作流程并提高生产率。 本文涵盖…

灰色GM(1,1)模型及其在电力负荷预测中的应用附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

【每日一题】LFU 缓存

一个缓存结构需要实现如下功能&#xff1a; void set(int key,int value)&#xff1a;加入或者修改 key 对应的 value int get(int key)&#xff1a;查询 key 对应的 value 值 但是缓存最多放 K 条记录&#xff0c;如果新的 K 1 条记录需要加入&#xff0c;就需要根据策略删掉…

【面试题】如何替换项目中的if-else和switch

给大家推荐一个实用面试题库 1、前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 在项目中&#xff0c;往往会看到很多的if-else或者switch&#xff0c;项目会变得很臃肿&#xff0c;而且不易阅读&…

速溶颗粒:实验中的好伙伴

缓冲溶液 (buffer solution) 通常是由弱酸及其盐、弱碱及其盐组成的混合溶液&#xff0c;能在一定程度上抵消、减轻外加强酸或强碱对溶液酸碱度的影响&#xff0c;从而保持溶液的 pH 值相对稳定。 传统的缓冲液配制过程可简单概括为计算——称量——溶解——定容。而生物学上常…

windows10提权

参照tryhackme的win10提权靶场 靶场&#xff0c;地址 里面共描述了服务路径&#xff0c;文件权限&#xff0c;计划任务&#xff0c;令牌窃取&#xff0c;图形化软件&#xff0c;应用组件安装等&#xff0c;这里只有令牌窃取需要管理员Administrator权限&#xff0c;值得注意的是…

向毕业妥协系列之机器学习笔记:无监督学习-聚类

目录 序言 一.什么是聚类 二.K-means算法 三.优化目标 四.初始化K-means 五.选择聚类数量&#xff08;k?&#xff09; 序言 第三课这块要学习的几块知识如下&#xff1a; 在学完监督学习之后&#xff0c;接下来我们要学习的东西分别是聚类&#xff0c;异常检测&#xf…

Spring 源码阅读 74:事务管理的原理 - BeanFactoryTransactionAttributeSourceAdvisor 分析

本文通过对 BeanFactoryTransactionAttributeSourceAdvisor 类的分析&#xff0c;了解了 Spring 是如何通过 AOP 来完成事务的管理的&#xff0c;本文的内容需要你对 Spring 的 AOP 的实现原理有一定的了解。 基于 Spring Framework v5.2.6.RELEASE 概述 Spring 的事务管理基于…

基于 Flask-Admin 与 AdminLTE 构建通用后台管理系统

Flask-Admin 是什么&#xff1f; Flask-Admin 官网文档中给出了其功能定位&#xff1a; Why Flask-Admin? In a world of micro-services and APIs, Flask-Admin solves the boring problem of building an admin interface on top of an existing data model. With little e…

SAP 公司代码全局参数设置及其意义

在SAP中配置公司时&#xff0c;会配置公司的全局参数&#xff0c;但这些参数具体的意思是什么估计很多同学都搞不懂&#xff0c;我也找了下资料&#xff0c;贴出来供大家参考。 设置参数路径&#xff1a;IMG→财务会计→财务会计全局设置→公司代码的全球参数→输入全局参数 账…

教你几个手机识别图片中的文字小技巧

平时我们在工作&#xff0c;有时候会拿到需要录入的纸质文件&#xff0c;如果我们使用双手逐一对照录入的话&#xff0c;就太浪费时间了。其实还有一个更简单的方法&#xff0c;就是将需要录入的文件拍摄下来&#xff0c;借助工具将图片内容转写为文字出来&#xff0c;再将其复…

Python Flask框架-开发简单博客-认证蓝图

作者&#xff1a;Eason_LYC 悲观者预言失败&#xff0c;十言九中。 乐观者创造奇迹&#xff0c;一次即可。 一个人的价值&#xff0c;在于他所拥有的。可以不学无术&#xff0c;但不能一无所有&#xff01; 技术领域&#xff1a;WEB安全、网络攻防 关注WEB安全、网络攻防。我的…

最新定制的安卓项目及设计报告——仿番茄小说APP

已录演示视频&#xff0c;想看演示视频的可以私我 《移动应用开发实践》实践报告 APP名称&#xff1a; 番茄免费小说 要求&#xff1a; 格式&#xff1a;宋体&#xff0c;小四号字&#xff1b;首行缩进&#xff1b;行距&#xff1a;1.5倍。 每人独立完成Android App的设计…

三步学会如何构建平衡二叉树(简单好理解)

何为平衡二叉树? 首先回顾一下&#xff0c;什么是平衡二叉树&#xff08;亦被称为AVL树&#xff0c;Adelson-Velskii and Landis&#xff09;。平衡二叉树主要具有以下三个特点&#xff1a; 1. 平衡二叉树首先要符合搜索二叉树的特点&#xff1a;即左子树的值比根节点小&…

排序算法之归并排序

目录 归并排序递归实现 思想 图解 代码 归并排序的非递归版本 基本思想&#xff1a; 代码 归并排序递归实现 思想 最主要的相当于二叉树遍历中的后序遍历。 ①将数组分割成多个小区间&#xff08;当只有一个元素或者并不存在的时候就不用再分割了&#xff09; ②对每一…

某工控图片上传服务 CPU 爆高分析

一&#xff1a;背景 1.讲故事 今天给大家带来一个入门级的 CPU 爆高案例&#xff0c;前段时间有位朋友找到我&#xff0c;说他的程序间歇性的 CPU 爆高&#xff0c;不知道是啥情况&#xff0c;让我帮忙看下&#xff0c;既然找到我&#xff0c;那就用 WinDbg 看一下。 二&…

Linux进程概念和控制(必备知识)

文章目录1、冯诺依曼体系结构2、操作系统3、进程<1>进程的创建<2>进程查看<3>进程状态<4>进程优先级<5> 进程地址空间4、环境变量5、进程控制<1>进程终止<2>进程等待<3>进程替换1、冯诺依曼体系结构 我们常见的计算机&#x…

软考 - 软件工程

软件过程基本概述 基本要素 方法工具过程 软件过程模型 能力成熟度模型CMM 能力成熟度模型CMMI 统一过程UP模型 针对大型项目 三大特别 用例和风险驱动以架构为中心迭代并且增量 四个阶段 起始&#xff1a;确认需求和风险评估精化&#xff1a;核心架构设计构建&#xff1a;构…