FreeRTOS深入教程(信号量源码分析)

文章目录

  • 前言
  • 一.创建信号量
  • 二.释放信号量
  • 三.获取信号量
    • 成功获取
    • 获取不成功
  • 总结


前言

本篇文章将为大家讲解信号量,源码分析。

在 FreeRTOS 中,信号量的实现基于队列。这种设计的思想是利用队列的特性来实现信号量,因为信号量可以被视为只能存储 0 或 1 个元素的特殊队列。

在 FreeRTOS 中,二进制信号量(Binary Semaphore)通常由一个队列和一个计数器组成。

计数信号量允许计数器的值大于 1,它通常用于管理多个相同资源的可用性。计数信号量的值表示可用资源的数量,多个任务可以同时获取不同数量的资源。当任务获取资源时,计数器减少,当任务释放资源时,计数器增加。

一.创建信号量

创建二进制信号量

xBinarySemaphore = xSemaphoreCreateBinary();

创建信号量源码分析:

创建信号量时本质上还是使用到了xQueueGenericCreate队列相关的函数
在这里插入图片描述
信号量不能用来进行数据的传输,所以在创建信号量时Itemsize被设置为了0。
在这里插入图片描述
在这里插入图片描述
将pucQueueStorage指针指向队列的存储区域位置。

在这里插入图片描述
在这里插入图片描述

初始化队列:

在这里插入图片描述
根据uxItemSize是否为0调整pcHead的指向。
在这里插入图片描述
对uxLength和uxItemSize进行赋值。

在这里插入图片描述

创建计数型信号量:

创建计数型信号量使用到了xQueueCreateCountingSemaphore函数。
在这里插入图片描述
使用这个函数时需要开启configUSE_COUNTING_SEMAPHORES和configSUPPORT_DYNAMIC_ALLOCATION这两个宏。

在这里插入图片描述
创建计数型信号量时还是会使用到xQueueGenericCreate函数进行创建。

唯一的区别就是二值信号量的uxMessagesWaiting参数只能是0或者1,而计数型信号量的uxMessagesWaiting可以为任意的值(0和正数)。
在这里插入图片描述

二.释放信号量

由于释放信号量会涉及到访问共享资源,所以开始先关闭中断。

taskENTER_CRITICAL();

判断pxQueue->uxMessagesWaiting是否小于pxQueue->uxLength,如果小于,调用prvCopyDataToQueue函数让uxMessagesWaiting的值加1。

if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
{
	.........
	xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
}

在这里插入图片描述
判断是否有任务在等待信号量,有的话移除并且唤醒任务优先级最高的任务。

                        if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
                        {
                            if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
                            {
                                /* The unblocked task has a priority higher than
                                 * our own so yield immediately.  Yes it is ok to do
                                 * this from within the critical section - the kernel
                                 * takes care of that. */
                                queueYIELD_IF_USING_PREEMPTION();
                            }
                            else
                            {
                                mtCOVERAGE_TEST_MARKER();
                            }
                        }

由于xSemaphoreGive函数不涉及超时参数,故不涉及超时处理。

三.获取信号量

成功获取

由于获取信号量会涉及到访问共享资源,所以开始先关闭中断。

taskENTER_CRITICAL();

获取当前count值

const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting;

判断uxSemaphoreCount是否大于0,大于0则uxMessagesWaiting的值减1。

            if( uxSemaphoreCount > ( UBaseType_t ) 0 )
            {
                traceQUEUE_RECEIVE( pxQueue );

                /* Semaphores are queues with a data size of zero and where the
                 * messages waiting is the semaphore's count.  Reduce the count. */
                pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1;

获取不成功

当获取不成功,并且没有设置超时时间直接返回错误:

                if( xTicksToWait == ( TickType_t ) 0 )
                {
                    /* For inheritance to have occurred there must have been an
                     * initial timeout, and an adjusted timeout cannot become 0, as
                     * if it were 0 the function would have exited. */
                    #if ( configUSE_MUTEXES == 1 )
                        {
                            configASSERT( xInheritanceOccurred == pdFALSE );
                        }
                    #endif /* configUSE_MUTEXES */

                    /* The semaphore count was 0 and no block time is specified
                     * (or the block time has expired) so exit now. */
                    taskEXIT_CRITICAL();
                    traceQUEUE_RECEIVE_FAILED( pxQueue );
                    return errQUEUE_EMPTY;//返回错误
                }

设置超时时间

                else if( xEntryTimeSet == pdFALSE )
                {
                    /* The semaphore count was 0 and a block time was specified
                     * so configure the timeout structure ready to block. */
                    vTaskInternalSetTimeOutState( &xTimeOut );
                    xEntryTimeSet = pdTRUE;
                }

检查是否超时,并且放入xTasksWaitingToReceive链表中。

        if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
        {
            /* A block time is specified and not expired.  If the semaphore
             * count is 0 then enter the Blocked state to wait for a semaphore to
             * become available.  As semaphores are implemented with queues the
             * queue being empty is equivalent to the semaphore count being 0. */
            if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
            {
                traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );

                #if ( configUSE_MUTEXES == 1 )
                    {
                        if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
                        {
                            taskENTER_CRITICAL();
                            {
                                xInheritanceOccurred = xTaskPriorityInherit( pxQueue->u.xSemaphore.xMutexHolder );
                            }
                            taskEXIT_CRITICAL();
                        }
                        else
                        {
                            mtCOVERAGE_TEST_MARKER();
                        }
                    }
                #endif /* if ( configUSE_MUTEXES == 1 ) */

                vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
                prvUnlockQueue( pxQueue );

超时直接返回错误

        else
        {
            /* Timed out. */
            prvUnlockQueue( pxQueue );
            ( void ) xTaskResumeAll();

            /* If the semaphore count is 0 exit now as the timeout has
             * expired.  Otherwise return to attempt to take the semaphore that is
             * known to be available.  As semaphores are implemented by queues the
             * queue being empty is equivalent to the semaphore count being 0. */
            if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
            {
                #if ( configUSE_MUTEXES == 1 )
                    {
                        /* xInheritanceOccurred could only have be set if
                         * pxQueue->uxQueueType == queueQUEUE_IS_MUTEX so no need to
                         * test the mutex type again to check it is actually a mutex. */
                        if( xInheritanceOccurred != pdFALSE )
                        {
                            taskENTER_CRITICAL();
                            {
                                UBaseType_t uxHighestWaitingPriority;

                                /* This task blocking on the mutex caused another
                                 * task to inherit this task's priority.  Now this task
                                 * has timed out the priority should be disinherited
                                 * again, but only as low as the next highest priority
                                 * task that is waiting for the same mutex. */
                                uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue );
                                vTaskPriorityDisinheritAfterTimeout( pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority );
                            }
                            taskEXIT_CRITICAL();
                        }
                    }
                #endif /* configUSE_MUTEXES */

                traceQUEUE_RECEIVE_FAILED( pxQueue );
                return errQUEUE_EMPTY;
            }

总结

本篇文章主要讲解了信号量,互斥量源码分析,其实信号量,互斥量是一个特殊的队列,掌握了队列后来学习信号量和互斥量的话那就是比较轻松的了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

路由VRRP配置例子

拓朴如下&#xff1a; 主要配置如下&#xff1a; [R1] interface GigabitEthernet0/0/0ip address 10.1.1.1 255.255.255.0 vrrp vrid 1 virtual-ip 10.1.1.254vrrp vrid 1 priority 200vrrp vrid 1 preempt-mode timer delay 20 # interface GigabitEthernet0/0/1ip address …

分布式事务总结

文章目录 一、分布式事务基础什么是事务&#xff1f;本地事物分布式事务分布式事务的场景 二、分布式事务解决方案全局事务可靠消息服务TCC 事务 三、Seata 分布式事务解决方案3.1 Seata-At模式3.2 秒杀项目集成 Seata启动 Seata-Server项目集成seata配置AT模式代码实现 3.3 Se…

【自主探索】基于 frontier_exploration 的单个机器人自主探索建图

文章目录 一、概述1、功能2、要求 二、使用方法1、用于运行演示2、用于开发人员2.1. 探索无/地图数据2.2. 使用 /map 数据进行探索 三、提供的组件1、explore_client1.1. 调用的操作1.2. 订阅主题1.3. 发布主题 2、explore_server2.1. 提供的操作2.2. 调用的操作2.3. 调用的服务…

AMESim与MATLAB联合仿真demo

本文是AMESim与MATLAB联合仿真的demo&#xff0c;记录一下如何进行联合仿真。 AMESim与MATLAB联合仿真可以大幅度提高工作效率。 author&#xff1a;xiao黄 缓慢而坚定的生长 csdn:https://blog.csdn.net/Python_Matlab?typeblog主页传送门 博主的联合仿真环境如下&#xff…

闲人闲谈PS之四十七——PS顾问能力评价参考标准

惯例闲话&#xff1a;逝者如斯夫&#xff0c;一晃2023年进入年尾&#xff0c;初步盘点下今年做的事情&#xff0c;还真不少&#xff0c;PLM项目、接口开发、扫码系统、数字彩虹图、专利申请…闲人发现&#xff0c;不经意间&#xff0c;SAP从自己的主营业务中占据的比重已经越来…

【21年扬大真题】编写程序,去除掉字符串中所有的星号。

【21年扬大真题】 编写程序&#xff0c;去除掉字符串中所有的星号。 int main() {int i 0;int j 0;char arr[30] {0};char brr[30] {0};printf("请输入一个字符串:");gets(arr);for (i 0;i < 30;i){if (arr[i] ! *) {brr[j] arr[i];j;}}int tmp j;for (i …

Nginx模块开发之http handler实现流量统计(2)

文章目录 一、概述二、Nginx handler模块开发2.1、代码实现2.2、编写config文件2.3、编译模块到Nginx源码中2.4、修改conf文件2.5、执行效果 总结 一、概述 上一篇【Nginx模块开发之http handler实现流量统计&#xff08;1&#xff09;】使用数组在单进程实现了IP的流量统计&a…

【ArcGIS Pro微课1000例】0036:栅格影像裁剪与提取(矢量范围裁剪dem高程数据)

本实验讲解在ArcGIS Pro中进行栅格影像裁剪与提取(矢量范围裁剪dem高程数据)的方法。DEM、DOM、DSM等栅格数据方法也可以实现。 文章目录 一、加载实验数据二、裁剪工具的使用1. 裁剪栅格2. 按掩膜提取一、加载实验数据 加载配套实验数据包中的0036.rar中的dem数据和矢量裁剪…

网工内推 | 美的、得力集团,包吃包住,IE认证优先,14薪

01 美的 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1.负责IT网络设备、IDC机房的日常维护巡检、监控和管理&#xff1b; 2.负责路由、交换、防火墙、无线控制器、AP等网络设备的开通、调整、优化升级&#xff1b; 3.负责公司OT、IT网络规划&#xff0c;项目实施以…

N-134基于java实现捕鱼达人游戏

开发工具eclipse,jdk1.8 文档截图&#xff1a; package com.qd.fish;import java.awt.Graphics; import java.io.File; import java.util.ArrayList; import java.util.List;import javax.imageio.ImageIO;public class Fishes {//定义一个集合来管理鱼List<Fish> fish…

安装compiler version 5

这个compiler version5 在我的资源里面可以免费下载&#xff1b; 另外这个东西还需要安装&#xff0c;安装教程在这里&#xff1a;Keil最新版保姆教程&#xff08;解决缺少V5编译器问题&#xff09; - 哔哩哔哩 (bilibili.com) 看吧安装好了year

Java自动装箱(autoboxing)和自动拆箱(autounboxing)介绍

Java自动装箱(autoboxing)和自动拆箱(autounboxing)介绍 先回顾一下 Java 中的基本数据类型和包装类。 基本数据类型&#xff08;Primitive Data Types&#xff09;&#xff1a; Java 提供了一组基本数据类型&#xff0c;有8种基本数据类型&#xff1a;byte、short、int、long…

旋转框检测项目相关python库知识总结

旋转框常用于检测带有角度信息的矩形框&#xff0c;即矩形框的宽和高不再与图像坐标轴平行。相较于水平矩形框&#xff0c;旋转矩形框一般包括更少的背景信息。旋转框检测常用于遥感等场景中&#xff0c;本博文简单的介绍了可应用于旋转框数据训练的开源库&#xff0c;数据结构…

Spring 七大组件

文章目录 Spring 七大组件 Spring 七大组件 核心容器(Spring core) 核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean&#xff0c;它是工厂模式的实现。BeanFactory使用控制反转(IOC)模式…

报错AttributeError: module ‘cv2‘ has no attribute ‘ximgproc‘

报错AttributeError: module ‘cv2’ has no attribute ‘ximgproc’ 首先查看是否安装opencv-contrib-python pip list | grep opencv显示 opencv-contrib-python 4.4.0.46 opencv-python 4.8.1.78 opencv-pyt…

Python 基础【五】--数据类型-序列【2023.11.24】

1.定义 Python 中的序列是一块可存放多个值的连续内存空间&#xff0c;所有值按一定顺序排列&#xff0c;每个值所在位置都有一个编号&#xff0c;称其为索引&#xff0c;我们可以通过索引访问其对应值。 list1 [Google, Runoob, 1997, 2000] list2 [1, 2, 3, 4, 5 ] list3…

【工具使用】Keil工具的使用——常用配置介绍

Keil调试具体教程学习 目录 ​​​​​​​Keil调试具体教程学习 常用功能总结 &#xff08;2&#xff09;目标设置&#xff08;Target&#xff09; ①设置晶振频率 ②跨模块优化选项 ③微库选项 &#xff08;3&#xff09;输出设置&#xff08;Output&#xff09; ①…

Java枚举详解

一、什么是枚举类型 枚举类型是一种特殊的数据类型&#xff0c;用于定义一组固定的命名常量。枚举类型提供了一种更强大、更安全和更易读的方式来表示一组相关的常量。 在Java中&#xff0c;枚举类型是通过使用enum关键字来定义的。枚举类型可以包含一个或多个枚举常量&#xf…

P1028 [NOIP2001 普及组] 数的计算

时刻记住一句话&#xff1a;写递归&#xff0c;1画图&#xff0c;2大脑放空&#xff01;&#xff01;&#xff01; 意思是&#xff0c;自己写递归题目&#xff0c;先用样例给的数据画图&#xff0c;然后想一个超级简单的思路&#xff0c;直接套上去就可以了。 上题干&#xff…

Theta*: Any-Angle Path Planning on Grids 原文翻译

Theta*: Any-Angle Path Planning on Grids 文章目录 Theta*: Any-Angle Path Planning on Grids翻译摘要1.Introduction2. Path-Planning Problem and Notation3. Existing Terrain Discretizations4.Existing Path-Planning Algorithms4.1 A* on GridsA* with Post-Smoothed …