当前位置: 首页 > news >正文

[FreeRTOS 内部实现] 信号量

文章目录

    • 基础知识
    • 创建信号量
    • 获取信号量
    • 释放信号量
    • 信号量 内部实现框图


基础知识

[FreeRTOS 基础知识] 信号量 概念


创建信号量

#define queueQUEUE_TYPE_BINARY_SEMAPHORE    ( ( uint8_t ) 3U )
#define semSEMAPHORE_QUEUE_ITEM_LENGTH    ( ( uint8_t ) 0U )
#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )

根据上面的定义,可知创建信号量本质就是创建队列。长度(第一个参数)为1,大小(第二个参数)为0

QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType )->     if( uxItemSize == ( UBaseType_t ) 0 ) xQueueSizeInBytes = ( size_t ) 0;->     pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes );  // 动态分配大小,只有一个Queue_t结构体大小

在这里插入图片描述


获取信号量

通过队列获取信号量

#define xSemaphoreTake( xSemaphore, xBlockTime )        xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait )for( ;; )
{taskENTER_CRITICAL();        // 关中断{const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting;    // 获取当前信号量值if( uxSemaphoreCount > ( UBaseType_t ) 0 )                            // 信号量值大于0{traceQUEUE_RECEIVE( pxQueue );pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1;    // 信号量-1// 检查是否有其他任务阻塞等待信号量。if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ){// 如果是,解除阻塞最高优先级的任务。// 1、将最高阻塞任务从xTasksWaitingToSend链表中移除;// 2、将最高阻塞任务从从DelayList移动到ReadyList链表if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ){queueYIELD_IF_USING_PREEMPTION();   // 让出CPU使用权}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}taskEXIT_CRITICAL();   //开中断return pdPASS;        // 返回成功}else{if( xTicksToWait == ( TickType_t ) 0 ) // 是否愿意等待{// 不愿意等待taskEXIT_CRITICAL();   // 打开中断traceQUEUE_RECEIVE_FAILED( pxQueue );return errQUEUE_EMPTY;   // 返回队列空失败}else if( xEntryTimeSet == pdFALSE ){// 信号量计数为0,阻塞时间被指定,所以配置超时结构准备阻塞。vTaskInternalSetTimeOutState( &xTimeOut );xEntryTimeSet = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}}taskEXIT_CRITICAL();vTaskSuspendAll();prvLockQueue( pxQueue );if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ){if( prvIsQueueEmpty( pxQueue ) != pdFALSE ){traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );// 1、当前的任务加入到队列的xTasksWaitingToReceive链表中;// 2、当前的任务从ReadyList移动到DelayListvTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );prvUnlockQueue( pxQueue );if( xTaskResumeAll() == pdFALSE ){portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}}        else{prvUnlockQueue( pxQueue );( void ) xTaskResumeAll();}}else{...}

释放信号量

#define semGIVE_BLOCK_TIME                    ( ( TickType_t ) 0U )
#define xSemaphoreGive( xSemaphore )        xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition )
-> for( ;; ){taskENTER_CRITICAL();    // 关中断 portDISABLE_INTERRUPTS();{if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )    // 判断当前信号量是否超过队列信号量长度{        traceQUEUE_SEND( pxQueue );xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );// 不会写数据,但是会将 uxMessagesWaiting +1if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )          // 判断xTasksWaitingToReceive队列里是否有等待的任务{if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) // 1、将要写的任务从xTasksWaitingToReceive移除;2、将要写的任务从DelayList移动到ReadyList{queueYIELD_IF_USING_PREEMPTION();    //让出CPU使用权}else{mtCOVERAGE_TEST_MARKER();}}                                else if( xYieldRequired != pdFALSE ){queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}taskEXIT_CRITICAL();    // 开中断return pdPASS;          // 返回成功}else{if( xTicksToWait == ( TickType_t ) 0 ){taskEXIT_CRITICAL();traceQUEUE_SEND_FAILED( pxQueue );return errQUEUE_FULL;         // 返回队列已满}else if( xEntryTimeSet == pdFALSE ){vTaskInternalSetTimeOutState( &xTimeOut ); // 阻塞时间被指定,所以配置超时结构。 xEntryTimeSet = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}
}
taskEXIT_CRITICAL();    // 开中断vTaskSuspendAll();
prvLockQueue( pxQueue );if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{if( prvIsQueueFull( pxQueue ) != pdFALSE ){traceBLOCKING_ON_QUEUE_SEND( pxQueue );// 1、当前的任务加入到队列的xTasksWaitingToSend链表中;// 2、当前的任务从ReadyList移动到DelayList                vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );prvUnlockQueue( pxQueue );if( xTaskResumeAll() == pdFALSE ){portYIELD_WITHIN_API();}}else{prvUnlockQueue( pxQueue );( void ) xTaskResumeAll();}
}
else
{prvUnlockQueue( pxQueue );( void ) xTaskResumeAll();traceQUEUE_SEND_FAILED( pxQueue );return errQUEUE_FULL;
}
}

信号量 内部实现框图

在这里插入图片描述

http://www.lryc.cn/news/382195.html

相关文章:

  • Vue57-组件的自定义事件_解绑
  • Java启动jar设置内存分配详解
  • Feign Client超时时间设置不生效问题
  • Haproxy部署Web群集
  • C++STL梳理
  • 找出1000以内的所有的完数
  • 3110. 字符串的分数
  • Mybatis MySQL allowMultiQueries 一次性执行多条语句
  • Kubernates容器化JVM调优笔记(内存篇)
  • Elasticsearch Scroll 报错entity content is too long
  • Vue iview输入框change事件replace正则替换不生效问题的解决。
  • Prestashop跨境电商独立站,外贸B2C网站完整教程
  • 常用算法及参考算法 (1)累加 (2)累乘 (3)素数 (4)最大公约数 (5)最值问题 (6)迭代法
  • java简易计算器(多种方法)
  • spring的bean定义和扫描规则
  • 软件工程体系概念
  • 史上最全整合nacos单机模式整合哈哈哈哈哈
  • Python xml.dom.minidom 读取XML元素
  • 【Python/Pytorch 】-- K-means聚类算法
  • 【Eureka】介绍与基本使用
  • SpringBoot+Vue集成富文本编辑器
  • React@16.x(34)动画(中)
  • ONLYOFFICE 8.1:全面升级,PDF编辑与本地化加强版
  • C++ 入门
  • GPT-5发布倒计时:AI智能从高中生到博士生的跨越
  • Docker 拉取镜像失败处理 配置使用代理拉取
  • 视频汇聚安防综合管理系统EasyCVR平台GB28181设备注册未上线的原因排查与解决
  • 【性能优化】Android冷启动优化
  • Git拉完整代码缺少某个类
  • Windows资源管理器down了,怎么解