首页 > 编程语言 >FreeRTOS深入教程(信号量源码分析)

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

时间:2023-11-24 20:31:35浏览次数:37  
标签:count FreeRTOS 队列 pxQueue 信号量 pdFALSE 源码 semaphore

(文章目录)


前言

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

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

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

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

一.创建信号量

创建二进制信号量

xBinarySemaphore = xSemaphoreCreateBinary();

创建信号量源码分析:

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

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

初始化队列:

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

在这里插入图片描述

创建计数型信号量:

二.释放信号量

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

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

总结

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

标签:count,FreeRTOS,队列,pxQueue,信号量,pdFALSE,源码,semaphore
From: https://blog.51cto.com/u_16153875/8551240

相关文章

  • 基于微信小程序的酒店管理系统设计与实现(源码+lw+部署文档+讲解等)
    (文章目录)详细视频演示请联系我获取更详细的演示视频具体实现截图[外链图片转存中...(img-Lkna8qpn-1700727246356)]技术栈后端框架SpringBootSpringBoot内置了Tomcat、Jetty和Undertow等服务器,这意味着你可以直接使用它们而不需要额外的安装和配置。SpringBoot的一......
  • 基于springboot,vue的教务管理系统源码 学生信息管理系统
    项目源码获取方式放在文章末尾处项目技术数据库:Mysql5.7数据表:9张开发语言:Java(jdk1.8)开发工具:idea前端技术:Vue后端技术:SpringBoot 项目源码获取方式放在文章末尾处功能简介该项目是一个教务管理系统,角色分为管理员,教师,学生三个角色,具体功能菜单如下:管理员端    登录    ......
  • PHP医院手术麻醉信息系统源码,实现手术申请与排班、审批、安排、术前、术中和术后的信
    医院手术麻醉信息系统全套商业源码,自主版权,支持二次开发手术麻醉信息系统是HIS产品的中的一个组成部分,主要应用于医院的麻醉科,属于电子病历类产品。医院麻醉监护的功能覆盖整个手术与麻醉的全过程,包括手术申请与排班、审批、安排、术前、术中和术后的信息管理提供支持。手术麻醉信......
  • 开源在线客服系统源码PHP(H5网页在线客服系统小程序源码uniapp全套搭建)
    现代客户服务的重要性得到了越来越多的认可。一个优质的客户服务可以使客户在购买和使用产品、寻求技术支持时获得更好的体验,从而建立起品牌声誉和客户忠诚度。为了优化客户服务体验,许多企业已经开始使用客服系统来更好地管理、响应和交互客户需求。源码:kf.zxkfym.top......
  • husky 源码浅析
    前言我们在上一篇中讲了自定义GitHook,那么前端同学有没有对husky的工作原理产生好奇呢,为什么husky可以让git执行他指定目录下的hooks目录呢?我们这一篇文章就带大家通过源码分析一下husky的工作原理,同时基于husky源码我们拓展讲一下如何使用Node.js编写cli......
  • 抖音UID转抖音号工具,可读取昵称、等级、地区【易语言源码学习】
    这个源码可以提取抖音UID的信息,调用的网页端的公开接口,正规接口哈,通过post实现,然后下面我会分享源码出来,仅供学习,不提供下载,源码大家可以学习交流。易语言源码【源码仅供学习,不提供成品下载】.版本2.支持库internet.程序集窗口程序集_启动窗口.子程序_按钮1_被单击......
  • Flink源码解析(六)——数据分区解析
    一、数据分区概念对分布式计算引擎来说,数据分区的主要作用是将现环节的数据进行切分,交给下游位于不同物理节点上的Task计算。二、Flink数据分区接口体系1、顶层接口ChannelSelector(1).setup()方法设置下游算子的通道数量。从该接口中可以看到,算子里的每一个分区器都知道下游......
  • Handler 源码解析,从入门到几乎入门
    AndroidHandler源码解析在Android中,Handler是一种强大的机制,用于在不同的线程之间进行通信。通过Handler,你可以轻松地将任务从一个线程发送到另一个线程,通常用于在后台线程执行任务后更新UI。同时handler机制也是Android主线程运行的原理,了解了主线程的运行原理也就可以知道l......
  • CreateIndex API执行流程_milvus源码解析
    CreateIndexAPI执行流程源码解析milvus版本:v2.3.2整体架构:CreateIndex的数据流向:1.客户端sdk发出CreateIndexAPI请求。importnumpyasnpfrompymilvusimport(connections,FieldSchema,CollectionSchema,DataType,Collection,)num_entities,......
  • CreateIndex API执行流程_milvus源码解析
    CreateIndexAPI执行流程源码解析milvus版本:v2.3.2整体架构:CreateIndex的数据流向:1.客户端sdk发出CreateIndexAPI请求。importnumpyasnpfrompymilvusimport(connections,FieldSchema,CollectionSchema,DataType,Collection,)num_entities,......