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

【11】FreeRTOS的延时函数

目录

  • 1.延时函数-介绍
  • 2.相对延时函数-解析
    • 2.1函数`prvAddCurrentTaskToDelayedList`-解析
    • 2.3滴答定时器中断服务函数`xPortSysTickHandler()`-解析
    • 2.4函数`taskSWITCH_DELAYED_LISTS() `-解析
  • 3.延时函数-实验
  • 4.总结

1.延时函数-介绍

函数描述
vTaskDelay()相对延时
xTaskDelayUntil()绝对延时

相对延时:指每次延时都是从执行函数vTaskDelay()开始,直到延时指定的时间结束(任务被阻塞的时间,到调用此函数开始的时间)
绝对延时:指将整个任务的运行周期看成一个整体,适用于需要按照一定频率运行的任务(整个任务执行的时间,从头到尾的时间)

在这里插入图片描述
上图中的xTimeIncrement为绝对延时时间(假如绝对延时时间为100ms,那么以下三部分之和为100ms),包括以下三部分:
(1)为任务主体,也就是任务真正要做的工作;
(2)是任务函数中调用vTaskDelayUntil()对任务进行延时;
(3)为其他任务在运行(高优先级的任务进行抢占)

2.相对延时函数-解析

首先入口参数必须大于0,延时时间有效。

void vTaskDelay( const TickType_t xTicksToDelay ){BaseType_t xAlreadyYielded = pdFALSE;/* A delay time of zero just forces a reschedule. */if( xTicksToDelay > ( TickType_t ) 0U )

vTaskSuspendAll()挂起任务调度器,traceTASK_DELAY()函数并没有被实现。 prvAddCurrentTaskToDelayedList(点击函数名可跳转至解析)
将当前正在执行的任务移到阻塞列表。

            vTaskSuspendAll();{traceTASK_DELAY();/* A task that is removed from the event list while the* scheduler is suspended will not get placed in the ready* list or removed from the blocked list until the scheduler* is resumed.** This task cannot be in an event list as it is the currently* executing task. */prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );}

恢复任务调度器。

            xAlreadyYielded = xTaskResumeAll();

判断xAlreadyYielded 是否需要进行任务切换。

        else{mtCOVERAGE_TEST_MARKER();}/* Force a reschedule if xTaskResumeAll has not already done so, we may* have put ourselves to sleep. */if( xAlreadyYielded == pdFALSE ){portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}}#endif /* INCLUDE_vTaskDelay */

此函数是将任务挂载到阻塞列表,解除是在滴答定时器的中断服务函数 xPortSysTickHandler()(点击函数名可跳转至解析)中。

2.1函数prvAddCurrentTaskToDelayedList-解析

函数prvAddCurrentTaskToDelayedList()有两个入口参数一个是延时时间xTicksToWait,另一个是xCanBlockIndefinitely 等于pdFALSE。

static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,const BaseType_t xCanBlockIndefinitely )

xConstTickCount 存储时钟节拍,滴答定时器中断一次,变量xTickCount加1。宏INCLUDE_xTaskAbortDelay 判断是否是中断延时,这里并没有使用,所以不用管。

{TickType_t xTimeToWake;const TickType_t xConstTickCount = xTickCount;#if ( INCLUDE_xTaskAbortDelay == 1 ){/* About to enter a delayed list, so ensure the ucDelayAborted flag is* reset to pdFALSE so it can be detected as having been set to pdTRUE* when the task leaves the Blocked state. */pxCurrentTCB->ucDelayAborted = pdFALSE;}#endif

将当前正在执行的任务的状态列表项使用函数uxListRemove()从就绪列表中移除,移除完判断是否有同等优先级的任务,没有就代表只有这一个任务,被移除掉后就绪列表中剩余任务为0,那么将此优先级的任务优先级复位。

    /* Remove the task from the ready list before adding it to the blocked list* as the same list item is used for both lists. */if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ){/* The current task must be in a ready list, so there is no need to* check, and the port reset macro can be called directly. */portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); /*lint !e931 pxCurrentTCB cannot change as it is the calling task.  pxCurrentTCB->uxPriority and uxTopReadyPriority cannot change as called with scheduler suspended or in a critical section. */}else{mtCOVERAGE_TEST_MARKER();}

INCLUDE_vTaskSuspend 判断是否使能挂起,判断延时时间xTicksToWait等于最大延时时间并且xCanBlockIndefinitely 不等于pdFALSE,此时将任务挂载到挂起列表中,由于传入参数为pdFALSE,所以不会挂载到挂起列表中,则执行else内容。

   #if ( INCLUDE_vTaskSuspend == 1 ){if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) ){/* Add the task to the suspended task list instead of a delayed task* list to ensure it is not woken by a timing event.  It will block* indefinitely. */listINSERT_END( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );}       

else中首先记录时间,xConstTickCount 为进入函数prvAddCurrentTaskToDelayedList()时记录的时间,加上延时时间xTicksToWait就是任务到截止阻塞时间该被恢复的时间;通过函数listSET_LIST_ITEM_VALUE将延时时间写入到列表项值里,此值将用作挂载到阻塞列表时根据此值进行升序排列;

          else{/* Calculate the time at which the task should be woken if the event* does not occur.  This may overflow but this doesn't matter, the* kernel will manage it correctly. */xTimeToWake = xConstTickCount + xTicksToWait;/* The list item will be inserted in wake time order. */listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );

判断需要等待截止的时间是否小于进入函数prvAddCurrentTaskToDelayedList()时记录的时间,这里判断是否数值溢出,如果溢出就将任务挂载到溢出阻塞列表中,否则挂载到阻塞列表中。

if( xTimeToWake < xConstTickCount ){/* Wake time has overflowed.  Place this item in the overflow* list. */vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );}else{/* The wake time has not overflowed, so the current block list* is used. */vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );

判断下一个阻塞超时时间如果大于新的阻塞时间,那么将新的阻塞时间更新为下一个阻塞超时时间。例如下一个xNextTaskUnblockTime 超时时间为30ms,新的阻塞时间xTimeToWake为20ms,肯定是20ms的先来到,所以将下一个阻塞超时时间更新为20ms。

                    /* If the task entering the blocked state was placed at the* head of the list of blocked tasks then xNextTaskUnblockTime* needs to be updated too. */if( xTimeToWake < xNextTaskUnblockTime ){xNextTaskUnblockTime = xTimeToWake;}else{mtCOVERAGE_TEST_MARKER();}}}}

2.3滴答定时器中断服务函数xPortSysTickHandler()-解析

函数xTaskIncrementTick()的值如果不等于pdFALSE,则进行任务切换,触发PendSV中断。

void xPortSysTickHandler( void )
{/* The SysTick runs at the lowest interrupt priority, so when this interrupt* executes all interrupts must be unmasked.  There is therefore no need to* save and then restore the interrupt mask value as its value is already* known - therefore the slightly faster vPortRaiseBASEPRI() function is used* in place of portSET_INTERRUPT_MASK_FROM_ISR(). */vPortRaiseBASEPRI();{/* Increment the RTOS tick. */if( xTaskIncrementTick() != pdFALSE ){/* A context switch is required.  Context switching is performed in* the PendSV interrupt.  Pend the PendSV interrupt. */portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;}}vPortClearBASEPRIFromISR();
}

在函数xTaskIncrementTick()中判断任务是否需要被解除。首先判断任务调度器是否被挂起,如果等于pdFALSE 则没有被挂起,进入if内容。

BaseType_t xTaskIncrementTick( void )
{TCB_t * pxTCB;TickType_t xItemValue;BaseType_t xSwitchRequired = pdFALSE;/* Called by the portable layer each time a tick interrupt occurs.* Increments the tick then checks to see if the new tick value will cause any* tasks to be unblocked. */traceTASK_INCREMENT_TICK( xTickCount );if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )

将系统时钟节拍xTickCount加1,然后再将值赋给自己,没进来一次时钟节拍将自加1。

/* Minor optimisation.  The tick count cannot change in this* block. */const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;/* Increment the RTOS tick, switching the delayed and overflowed* delayed lists if it wraps to 0. */xTickCount = xConstTickCount;

判断xConstTickCount 是否为0,为0则值溢出,进入函数 taskSWITCH_DELAYED_LISTS()(点击函数名可跳转至解析)

if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. */{taskSWITCH_DELAYED_LISTS();}else{mtCOVERAGE_TEST_MARKER();}/* See if this tick has made a timeout expire.  Tasks are stored in* the  queue in the order of their wake time - meaning once one task* has been found whose block time has not expired there is no need to* look any further down the list. */

判断当前时钟节拍ConstTickCount 是否大于等于下一个阻塞超时时间。

       /* See if this tick has made a timeout expire.  Tasks are stored in* the  queue in the order of their wake time - meaning once one task* has been found whose block time has not expired there is no need to* look any further down the list. */if( xConstTickCount >= xNextTaskUnblockTime ){for( ; ; ){

判断阻塞列表中是否有任务,如果没有任务则没有需要被解除的任务,则将下一个阻塞超时时间xNextTaskUnblockTime设置为最大值。

              if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ){/* The delayed list is empty.  Set xNextTaskUnblockTime* to the maximum possible value so it is extremely* unlikely that the* if( xTickCount >= xNextTaskUnblockTime ) test will pass* next time through. */xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */break;}

else则阻塞列表中有任务,通过函数listGET_OWNER_OF_HEAD_ENTRY()获取阻塞列表的第一个成员的任务控制块;通过函数listGET_LIST_ITEM_VALUE()获取列表项的数值,列表项中一般存放的是阻塞时间,则xItemValue被赋值阻塞时间。

               else{/* The delayed list is not empty, get the value of the* item at the head of the delayed list.  This is the time* at which the task at the head of the delayed list must* be removed from the Blocked state. */pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );

判断系统时间节拍的数值是否小于阻塞时间,代表此时发生异常。因为在首先进入if时判断了当前的系统时钟节拍比下一个阻塞超时时间大。此时将列表项的值赋值给下一个阻塞超时时间,退出。

if( xConstTickCount < xItemValue ){/* It is not time to unblock this item yet, but the* item value is the time at which the task at the head* of the blocked list must be removed from the Blocked* state -  so record the item value in* xNextTaskUnblockTime. */xNextTaskUnblockTime = xItemValue;break; /*lint !e9011 Code structure here is deemed easier to understand with multiple breaks. */}else{mtCOVERAGE_TEST_MARKER();}

下面的情况为正常执行的情况。使用函数listREMOVE_ITEM()将任务从阻塞列表中移除,同时也从使用函数listREMOVE_ITEM从事件列表中移除。

                    /* It is time to remove the item from the Blocked state. */listREMOVE_ITEM( &( pxTCB->xStateListItem ) );/* Is the task waiting on an event also?  If so remove* it from the event list. */if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ){listREMOVE_ITEM( &( pxTCB->xEventListItem ) );}else{mtCOVERAGE_TEST_MARKER();}

使用函数prvAddTaskToReadyList()将任务添加到就绪列表中,

                    /* Place the unblocked task into the appropriate ready* list. */prvAddTaskToReadyList( pxTCB );

判断宏configUSE_PREEMPTION是否使能抢占式任务调度,是则判断恢复的任务的任务优先级是否比当前正在执行的任务优先级高,是则将任务切换xSwitchRequired变量赋值pdTRUE。

                    /* A task being unblocked cannot cause an immediate* context switch if preemption is turned off. */#if ( configUSE_PREEMPTION == 1 ){/* Preemption is on, but a context switch should* only be performed if the unblocked task has a* priority that is equal to or higher than the* currently executing task. */if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ){xSwitchRequired = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_PREEMPTION */}}}

以下程序是时间片调度:

        /* Tasks of equal priority to the currently running task will share* processing time (time slice) if preemption is on, and the application* writer has not explicitly turned time slicing off. */#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ){if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 ){xSwitchRequired = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */#if ( configUSE_TICK_HOOK == 1 ){/* Guard against the tick hook being called when the pended tick* count is being unwound (when the scheduler is being unlocked). */if( xPendedTicks == ( TickType_t ) 0 ){vApplicationTickHook();}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_TICK_HOOK */#if ( configUSE_PREEMPTION == 1 ){if( xYieldPending != pdFALSE ){xSwitchRequired = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_PREEMPTION */}else{++xPendedTicks;/* The tick hook gets called at regular intervals, even if the* scheduler is locked. */#if ( configUSE_TICK_HOOK == 1 ){vApplicationTickHook();}#endif}return xSwitchRequired;
}

2.4函数taskSWITCH_DELAYED_LISTS() -解析

只溢出之后,将就绪列表pxDelayedTaskList和溢出就绪列表pxOverflowDelayedTaskList进行互换。

/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick* count overflows. */
#define taskSWITCH_DELAYED_LISTS()                                                \{                                                                             \List_t * pxTemp;                                                          \\/* The delayed tasks list should be empty when the lists are switched. */ \configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );               \\pxTemp = pxDelayedTaskList;                                               \pxDelayedTaskList = pxOverflowDelayedTaskList;                            \pxOverflowDelayedTaskList = pxTemp;                                       \xNumOfOverflows++;                                                        \prvResetNextTaskUnblockTime();                                            \}

3.延时函数-实验

1、实验目的:学习 FreeRTOS 相对延时和绝对延时API 函数的使用,并了解其区别
2、实验设计:将设计三个任务:start_task、task1,task2 三个任务的功能如下:
start_task:用来创建task1和task2任务 task1用于展示相对延时函数vTaskDelay ( )的使用;
task1:用于展示相对延时函数vTaskDelay ( )的使用;
task2:用于展示绝对延时函数vTaskDelayUntil( )的使用 。
为了直观显示两个延时函数的区别,将使用LED0(PB1) 和LED1(PB0) 的翻转波形来表示

1.首先删除无关的程序内容,task1和task2程序如下,其他程序保持不变。

/* 任务1,用于展示相对延时函数vTaskDelay ( )的使用 */
void task1( void * pvParameters )
{while(1){LED0=~LED0;vTaskDelay(500);}
}
/* 任务2,用于展示绝对延时函数vTaskDelayUntil( )的使用 */
void task2( void * pvParameters )
{while(1){vTaskDelay(10);}
}

2.task1中的本身就是使用的相对于延时,相对于调用的时候起,到延时时间结束,所以不用改变;task2在使用绝对延时函数vTaskDelayUntil()时,可以查看FreeRTOS官网对该函数的使用介绍,根据示例来编写函数使用,绝对延时是整个task2运行的时间。
在这里插入图片描述
由于LED翻转语句执行较快基本看不到差距,所以这里加了死延时。

/* 任务1,用于展示相对延时函数vTaskDelay ( )的使用 */
void task1( void * pvParameters )
{while(1){LED0=~LED0;delay_ms(20);vTaskDelay(500);}
}
/* 任务2,用于展示绝对延时函数vTaskDelayUntil( )的使用 */
void task2( void * pvParameters )
{TickType_t xLastWakeTime;xLastWakeTime = xTaskGetTickCount(); /* 获取当前的系统时钟节拍 */while(1)	{LED1=~LED1;delay_ms(20);vTaskDelayUntil(&xLastWakeTime,500);}
}

这里由于手头没有示波器,我并没有做出实验结果,理论结果如下。
理论实验结果
由于task1和task2都加了死延时20ms,LED0翻转周期为520ms左右,而LED1的翻转周期仍为500ms。由于task2优先级比task1要高,task2会抢占task1,所以在执行时,会出现task1处于阻塞延时时结束时,task2处于死延时,此时并不能进行任务切换,task1会等到task2死延时结束进入阻塞延时再运行,LED0的亮灭时间会有所变化,LED0亮灭时间会变长,LED1的亮灭周期为500ms保持不变。将task1的优先级变高,将会影响task2的绝对延时时间。

4.总结

在这里插入图片描述

相关文章:

【11】FreeRTOS的延时函数

目录1.延时函数-介绍2.相对延时函数-解析2.1函数prvAddCurrentTaskToDelayedList-解析2.3滴答定时器中断服务函数xPortSysTickHandler()-解析2.4函数taskSWITCH_DELAYED_LISTS() -解析3.延时函数-实验4.总结1.延时函数-介绍 函数描述vTaskDelay()相对延时xTaskDelayUntil()绝对…...

Vue页面组成及常用属性

一、Vue页面组成 目前的项目中&#xff0c;Vue页面都是采用组件套娃的形式&#xff0c;由一个一个的组件拼接而成整个页面。一个组件就是一个.vue文件。组件通常由template和script两部分组成&#xff1a; template部分&#xff1a;页面展示的具体元素内容&#xff0c;比如文字…...

j6-IO流泛型集合多线程注解反射Socket

IO流 1 JDK API的使用 2 io简介 输入流用来读取in 输出流用来写出Out 在Java中&#xff0c;根据处理的数据单位不同&#xff0c;分为字节流和字符流 继承结构 java.io包&#xff1a; File 字节流&#xff1a;针对二进制文件 InputStream --FileInputStream --BufferedInputStre…...

创业能否成功?这几个因素很重要!

创业能否成功&#xff1f;这几个因素很重要&#xff01; 2023-02-22 19:06:53 大家好&#xff0c;我是你们熟悉而又陌生的好朋友梦龙&#xff0c;一个创业期的年轻人 上周末跟朋友一起钓鱼&#xff0c;他跟吐槽现在生意越来越难做。他是我身边可以说是创业很成功的例子&#…...

Bmp图片格式介绍

Bmp图片格式介绍 介绍 BMP是英文Bitmap&#xff08;位图&#xff09;的简写&#xff0c;它是Windows操作系统中的标准图像文件格式&#xff0c;能够被多种Windows应用程序所支持。随着Windows操作系统的流行与丰富的Windows应用程序的开发&#xff0c;BMP位图格式理所当然地被…...

Day4 leetcode

Day4 啊啊啊啊&#xff0c;什么玩意&#xff0c;第一次因为测评没过&#xff0c;约好的面试取消了&#xff0c;好尴尬呀&#xff0c;还有一家厦门的C/C电话面&#xff0c;是一家我还挺喜欢的公司&#xff0c;面的稀烂&#xff0c;只能安慰自己我现在手上至少有一个offer 有效括…...

Java设计模式-原型模式

1、定义 原型模式是一种创建型模式&#xff0c;用于创建重复的对象&#xff0c;并且保证性能。原型模式创建的对象是由原型对象自身创建的&#xff0c;是原型对象的一个克隆&#xff0c;和原型对象具有相同的结构和相同的值。 2、适用场景 创建对象时我们不仅仅需要创建一个新…...

2023年度最新且最详细Ubuntu的安装教程

目录 准备ISO镜像 1.去官网下载镜像&#xff0c;或者找有镜像源的网站下载 阿里云镜像站 2. 如果服务器是打算直接把底层系统安装为Ubuntu的话还需制作系统U盘 安装 1.新建虚拟机调整基础配置 2.打开电源&#xff0c;进入安装界面&#xff08;到这一步就跟u盘安装步骤一致…...

unix高级编程-fork之后父子进程共享文件

~/.bash_profile:每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件. 这里我看到的是centos的操作&#xff0c;但我用的是debian系的ubuntu&#xff0c;百度了一下发现debian的在这里…...

vue+echarts:柱状图横向展示和竖向展示

第021个点击查看专栏目录本示例是显示柱状图&#xff0c;分别是横向展示和纵向展示。关键是X轴和Y轴的参数互换。 文章目录横向示例效果横向示例源代码&#xff08;共81行&#xff09;纵向示例效果纵向示例源代码&#xff08;共81行&#xff09;相关资料参考专栏介绍横向示例效…...

SealOS 一键安装 K8S

环境 # 查看系统发行版 $ cat /etc/os-release NAME"CentOS Linux" VERSION"7 (Core)" ID"centos" ID_LIKE"rhel fedora" VERSION_ID"7" PRETTY_NAME"CentOS Linux 7 (Core)" ANSI_COLOR"0;31" CPE_NA…...

python网络编程详解

最近在看《UNIX网络编程 卷1》和《FREEBSD操作系统设计与实现》这两本书&#xff0c;我重点关注了TCP协议相关的内容&#xff0c;结合自己后台开发的经验&#xff0c;写下这篇文章&#xff0c;一方面是为了帮助有需要的人&#xff0c;更重要的是方便自己整理思路&#xff0c;加…...

ICRA 2023 | 首个联合暗光增强和深度估计的自监督方法STEPS

原文链接&#xff1a;https://www.techbeat.net/article-info?id4629 作者&#xff1a;郑宇鹏 本文中&#xff0c;我们提出了STEPS&#xff0c;第一个自监督框架来联合学习图像增强和夜间深度估计的方法。它可以同时训练图像增强网络和深度估计网络&#xff0c;并利用了图像增…...

基于react+nodejs+mysql开发用户中心,用于项管理加入的项目的用户认证

基于reactnodejsmysql开发用户中心&#xff0c;用于项管理加入的项目的用户认证用户中心功能介绍页面截图后端采用架构user表projects表project_user表仓库地址用户中心功能介绍 用户中心项目&#xff0c;用于统一管理用户信息、登录、注册、鉴权等 功能如下&#xff1a; 用…...

mapreduce与yarn

文章目录一、MapReduce1.1、MapReduce思想1.2、MapReduce实例进程1.3、MapReduce阶段组成1.4、MapReduce数据类型1.5、MapReduce关键类1.6、MapReduce执行流程1.6.1、Map阶段执行流程1.6.2、Map的shuffle阶段执行流程1.6.3、Reduce阶段执行流程1.7、MapReduce实例WordCount二、…...

鲲鹏云服务器上使用 traceroute 命令跟踪路由

traceroute 命令跟踪路由 它由遍布全球的几万局域网和数百万台计算机组成&#xff0c;并通过用于异构网络的TCP/IP协议进行网间通信。互联网中&#xff0c;信息的传送是通过网中许多段的传输介质和设备&#xff08;路由器&#xff0c;交换机&#xff0c;服务器&#xff0c;网关…...

代码随想录算法训练营第47天 || 198.打家劫舍 || 213.打家劫舍II || 337.打家劫舍III

代码随想录算法训练营第47天 || 198.打家劫舍 || 213.打家劫舍II || 337.打家劫舍III 198.打家劫舍 题目介绍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&…...

JVM调优方式

对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数。 1.Full GC 会对整个堆进行整理&#xff0c;包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收&#xff0c;所以比较慢&#xff0c;因此应该尽可能减少Full GC的次数。 2.导致Full GC的原因 1)年老…...

机器学习模型监控的 9 个技巧

机器学习 (ML) 模型是非常敏感的软件&#xff1b;它们的成功使用需要进行仔细监控以确保它们可以正常工作。当使用所述模型的输出自动做出业务决策时尤其如此。这意味着有缺陷的模型通常会对终端客户的体验产生真正的影响。因此&#xff0c;监控输入数据&#xff08;和输出&…...

Linux 实现鼠标侧边键实现代码与网页的前进、后退

前言 之前一直是使用windows进行开发&#xff0c;最近转到linux后使用VsCode编写代码。 但是不像在win环境下&#xff0c;使用鼠标侧边键可以实现代码的前向、后向跳转。浏览网页时也不行&#xff08;使用Alt Left可以后退&#xff09;。 修改键盘映射实在没有那么方便&…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

tauri项目,如何在rust端读取电脑环境变量

如果想在前端通过调用来获取环境变量的值&#xff0c;可以通过标准的依赖&#xff1a; std::env::var(name).ok() 想在前端通过调用来获取&#xff0c;可以写一个command函数&#xff1a; #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道

文/法律实务观察组 在债务重组领域&#xff0c;专业机构的核心价值不仅在于减轻债务数字&#xff0c;更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明&#xff0c;合法债务优化需同步实现三重平衡&#xff1a; 法律刚性&#xff08;债…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究

摘要&#xff1a;在消费市场竞争日益激烈的当下&#xff0c;传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序&#xff0c;探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式&#xff0c;分析沉浸式体验的优势与价值…...