FreeRTOS_空闲任务

目录

1. 空闲任务详解

1.1 空闲任务简介

1.2 空闲任务的创建

1.3 空闲任务函数

2. 空闲任务钩子函数详解

2.1 钩子函数

2.2 空闲任务钩子函数

3. 空闲任务钩子函数实验

3.1 main.c


        空闲任务是 FreeRTOS 必不可少的一个任务,其他 RTOS 类系统也有空闲任务,比如 UCOS。顾名思义,空闲任务就是处理器空闲的时候去运行的一个任务,当系统中没有其他就绪任务的时候空闲任务就会开始运行,空闲任务最重要的作用就是让处理器在无事可做的时候找点事做,防止处理器无聊,因此,空闲任务的优先级必然是最低的。当然是实际中,必然不会如此浪费宝贵的处理器资源,FreeRTOS 空闲任务中也会执行一些其他的处理。

1. 空闲任务详解

1.1 空闲任务简介

        当 FreeRTOS 的调度器启动以后就会自动的创建一个空闲任务,这样就可以确保至少有一个任务可以运行。但是这个空闲任务使用最低优先级,如果应用中有其他高优先级任务处于就绪态的话这个空闲任务就不会跟高优先级的任务抢占 CPU 资源。空闲任务还有另外一个重要的职责,如果某个任务要调用函数 vTaskDelete() 删除自身,那么这个任务的任务控制块 TCB 和任务堆栈等这些由 FreeRTOS 系统自动分配的内存需要在空闲任务中释放掉,如果删除的是别的任务那么相应的内存就会被直接释放掉,不需要在空闲任务中释放。因此,一定要给空闲任务执行的机会!除此以外空闲任务就没有什么特别重要的功能了,所以可以根据实际情况减少空闲任务使用 CPU 的时间(比如,当 CPU 运行空闲任务的时候使处理器进入低功耗模式)。

        用户可以创建与空闲任务优先级相同的应用任务,当宏 configIDLE_SHOULD_YIELD 为 1 的话应用任务就可以使用空闲任务的时间片,也就是说空闲任务会让出时间片给同优先级的应用程序。

1.2 空闲任务的创建

        当调用函数 vTaskStartScheduler() 启动任务调度器的时候此函数就会自动创建空闲任务,代码如下:

void vTaskStartScheduler( void ) 
{ BaseType_t xReturn; //创建空闲任务,使用最低优先级 #if( configSUPPORT_STATIC_ALLOCATION == 1 )                                 (1) 使用静态方法创建空闲任务{ StaticTask_t *pxIdleTaskTCBBuffer = NULL; StackType_t *pxIdleTaskStackBuffer = NULL; uint32_t ulIdleTaskStackSize; vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer,&ulIdleTaskStackSize ); xIdleTaskHandle = xTaskCreateStatic( prvIdleTask, "IDLE", ulIdleTaskStackSize, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), pxIdleTaskStackBuffer, pxIdleTaskTCBBuffer ); if( xIdleTaskHandle != NULL ) { xReturn = pdPASS; } else { xReturn = pdFAIL; } } #else                                                                       (2) 使用动态方法创建空闲任务,空闲任务的任务函数为 prvIdleTask(),任务堆栈大小为 configMINIMAL_STACK_SIZE,任务堆栈大小可以在 FreeRTOSConfig.h 中修改。任务优先级为 tskIDLE_PRIORITY,宏 tskIDLE_PRIORITY 为 0,说明空闲任务优先级最低,用户不能随意修改空闲任务的优先级!{ xReturn = xTaskCreate( prvIdleTask, "IDLE", configMINIMAL_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle ); } #endif             /* configSUPPORT_STATIC_ALLOCATION */ /*********************************************************************/ 
/**************************省略其他代码*******************************/ 
/*********************************************************************/ 
}

1.3 空闲任务函数

        空闲任务的任务函数为 prvIdleTask(),但是实际上是找不到这个函数的,因为它是通过宏定义来实现的,在文件 portmacro.h 中有如下宏定义:

#define portTASK_FUNCTION(vFunction,pvParameters) void vFunction(void *pvParameters)

        其中,portTASK_FUNCTION() 在文件 tasks.c 中有定义,它就是空闲任务的任务函数,源码如下:

static portTASK_FUNCTION( prvIdleTask, pvParameters )                             (1) 将此行展开就是 static void prvIdleTask(void *pvParameters),创建空闲任务的时候任务函数名就是 prvIdleTask()
{ ( void ) pvParameters; //防止报错 //本函数为 FreeRTOS 的空闲任务任务函数,当任务调度器启动以后空闲任务会自动创建 for( ;; ) { //检查是否有任务要删除自己,如果有的话就释放这些任务的任务控制块 TCB 和 //任务堆栈的内存 prvCheckTasksWaitingTermination();                                        (2) 调用函数 prvCheckTasksWaitingTermination 检查是否有需要释放内存的被删除任务,当有任务调用函数 vTaskDelete() 删除自身的话,此任务就会添加到列表 xTasksWaitingTermination 是否为空,如果不为空的话就依次将列表中所有任务对应的内存释放掉(任务控制块 TCB 和任务堆栈的内存)#if ( configUSE_PREEMPTION == 0 ) { //如果没有使用抢占式内核的话就强制进行一次任务切换查看是否有其他 //任务有效,如果有使用抢占式内核的话就不需要这一步,因为只要有任 //何任务有效(就绪)之后都会自动的抢夺 CPU 使用权 taskYIELD(); } #endif /* configUSE_PREEMPTION */ #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) (3) 使用抢占式内核并且 configIDLE_SHOULD_YIELD 为 1,说明空闲任务需要让出时间片给同优先级的其他就绪任务{ //如果使用抢占式内核并且使能时间片调度的话,当有任务和空闲任务共享 //一个优先级的时候,并且此任务处于就绪态的话空闲任务就应该放弃本时 //间片,将本时间片剩余的时间让给这个就绪任务。如果在空闲任务优先级 //下的就绪列表中有多个用户任务的话就执行这些任务。 if( listCURRENT_LIST_LENGTH(                                          (4) 检查优先级为 tskIDLE_PRIORITY(空闲任务优先级)的就绪任务列表是否为空,如果不为空的话就调用函数 taskYIELD() 进行一次任务切换。&( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) )> ( UBaseType_t ) 1 ) { taskYIELD(); } else { mtCOVERAGE_TEST_MARKER(); } } #endif #if ( configUSE_IDLE_HOOK == 1) { extern void vApplicationIdleHook( void ); //执行用户定义的空闲任务钩子函数,注意!钩子函数里面不能使用任何 //可以引起阻塞空闲任务的 API 函数。vApplicationIdleHook();                                              (5) 如果使能了空闲任务钩子函数的话就执行这个钩子函数,空闲任务钩子函数的函数名为 vApplicationIdleHook(),这个函数需要用户自行编写!在编写这个钩子函数的时候一定不能调用任何可以阻塞空闲任务的 API 函数。} #endif /* configUSE_IDLE_HOOK */ //如果使能了 Tickless 模式的话就执行相关的处理代码 #if ( configUSE_TICKLESS_IDLE != 0 )                                     (6) configUSE_TICKLESS_IDLE 不为 0,说明使能了 FreeRTOS 的低功耗 Tickless 模式。{ TickType_t xExpectedIdleTime; xExpectedIdleTime = prvGetExpectedIdleTime();                        (7) 调用函数 prvGetExpectedIdleTime() 获取处理器进入低功耗模式的时长,此值保存在变量 xExpectedIdleTime 中,单位为时钟节拍数if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )     (8) xExpectedIdleTime 的值要大于 configEXPECTED_IDLE_TIME_BEFORE_SLEEP 才有效{ vTaskSuspendAll();                                               (9) 处理 Tickless 模式,挂起任务调度器,其实就是起到临界段代码保护功能{ //调度器已经被挂起,重新采集一次时间值,这次的时间值可以 //使用 configASSERT( xNextTaskUnblockTime >= xTickCount ); xExpectedIdleTime = prvGetExpectedIdleTime();                (10) 重新获取一次时间值,这次的时间值是直接用于 portSUPPRESS_TICKS_AND_SLEEP() 的if( xExpectedIdleTime >=configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) { traceLOW_POWER_IDLE_BEGIN(); portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );       (11) 调用 portSUPPRESS_TICKS_AND_SLEEP() 进入低功耗 Tickless 模式traceLOW_POWER_IDLE_END(); } else { mtCOVERAGE_TEST_MARKER(); } } ( void ) xTaskResumeAll();                                       (12) 恢复任务调度器} else { mtCOVERAGE_TEST_MARKER(); } } #endif /* configUSE_TICKLESS_IDLE */ } 
} 

2. 空闲任务钩子函数详解

2.1 钩子函数

        FreeRTOS 中有多个钩子函数,钩子函数类似于回调函数,当某个功能(函数)执行的时候就会调用钩子函数,至于钩子函数的具体内容就由用户来编写。如果不需要使用钩子函数的话就什么也不用管,钩子函数是一个可选功能,可以通过宏定义来选择使用哪个钩子函数。

宏定义:                                                                                                        描述:

configUSE_IDLE_HOOK                                                 空闲任务钩子函数,空闲任务会调用此钩子函数                              

configUSE_TICK_HOOK                                                 时间片钩子函数,xTaskIncrementTick()会调用此钩子函数。此钩子函数最终会被节拍中断服务函数用,对于 STM32 来说就是

                                                                                           滴答定时器中断服务函数

configUSE_MALLOC_FAILED_HOOK                            内存申请失败钩子函数,当使用函数 pvPortMalloc() 申请内存失败的时候就会调用此钩子函数

configUSE_DAEMON_TASK_STARTUP_HOOK            守护(Daemon)任务启动钩子函数,守护任务也就是定时器服务任务

        钩子函数的使用方法基本相同,用户使能相应的钩子函数,然后自行根据实际需求编写钩子函数的内容。

2.2 空闲任务钩子函数

        在每个空闲任务运行周期都会调用空闲任务钩子函数,如果想在空闲任务优先级下处理某个任务有两种选择

1. 在空闲任务钩子函数中处理任务

        不管什么时候都要保证系统中至少有一个任务可以运行,因此绝对不能在空闲任务钩子函数中调用任何可以阻塞空闲任务的 API 函数,比如 vTaskDelay(),或者其他带有阻塞时间的信号量或队列操作函数。

2. 创建一个与空闲任务优先级相同的任务

        创建一个任务是最好的解决方法,但是这种方法也消耗更多的 RAM。

        要使用空闲任务钩子函数首先要在 FreeRTOSConfig.h 中将宏 configUSE_IDLE_HOOK 改为 1,然后编写空闲任务钩子函数 vApplicationIdleHook()。通常在空闲任务钩子函数中将处理器设置为低功耗模式来节省电能,为了与 FreeRTOS 自带的 Tickless 模式做区别,这里将这种低功耗的实现方法称之为通用低功耗模式。(因为几乎所有的 RTOS 系统都可以使用这种方法实现低功耗)。

        上图中总共有三个任务,它们分别是一个空闲任务(Idle),两个用户任务(Task1 和 Task2),其中空闲任务一共运行了三次,分别为(1)、(2)和(3),其中 T1 到 T12 是 12 个时刻,下面我们分别从这两种低功耗的实现方法去分析一下整个过程。

1. 通用低功耗模式

        如果使用通用低功耗模式的话每个滴答定时器中断都会将处理器从低功耗模式中唤醒,以(1)为例,在 T2 时刻处理器从低功耗模式中唤醒,但是接下来由于没有就绪的其他任务所以处理器又再一次进入低功耗模式。T2、T3 和 T4 这三个时刻都一样,反复的进入低功耗、退出低功耗,最理想的情况应该是从 T1 时刻就进入低功耗,然后在 T5 时刻退出。

        在(2)中空闲任务只工作了两个时钟节拍,但是也执行了低功耗模式的进入和退出,显然这个意义不大,因为进出低功耗也是需要时间的。

        (3)中空闲任务在 T12 时刻被某个外部中断唤醒,中断的具体处理过程在任务 2 (使用信号量实现中断与任务之间的同步)。

2. 低功耗 Tickless 模式

        在(1)中的 T1 时刻处理器进入低功耗模式,在 T5 时刻退出低功耗模式。相比通用低功耗模式少了 3 次进出低功耗模式的操作。

        在(2)中由于空闲任务只运行了两个时钟节拍,所以就没必要进入低功耗模式。说明在 Tickless 模式中只有空闲任务要运行时间超过某个最小阈值的时候才会进入低功耗模式,此阈值通过 configEXPECTED_IDLE_TIME_BEFORE_SLEEP 来设置。

        (3)中的情况和通用低功耗模式一样。

        可以看出相对于通用低功耗模式,FreeRTOS 自带的 Tickless 模式更加合理有效,所以如果有低功耗设计需求的话大家尽量使用 FreeRTOS 自带的 Tickless 模式。

3. 空闲任务钩子函数实验

        本实验学习如何在 FreeRTOS 空闲任务钩子函数中实现低功耗。在空闲任务钩子函数中使用 WFI 指令使处理器进入睡眠模式。

3.1 main.c

#include "stm32f4xx.h"  
#include "FreeRTOS.h" //这里注意必须先引用FreeRTOS的头文件,然后再引用task.h
#include "task.h"     //存在一个先后的关系
#include "LED.h"
#include "LCD.h"
#include "Key.h"
#include "usart.h"
#include "delay.h"
#include "string.h"
#include "beep.h"
#include "malloc.h"
#include "timer.h"
#include "queue.h"
#include "semphr.h"//任务优先级
#define START_TASK_PRIO     1     //用于创建其他两个任务
//任务堆栈大小
#define START_STK_SIZE      256
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);//任务优先级
#define TASK1_TASK_PRIO     2   //控制 LED0 闪烁,提示系统正在运行
//任务堆栈大小
#define TASK1_STK_SIZE      256
//任务句柄
TaskHandle_t Task1Task_Handler;
//任务函数
void task1_task(void *pvParameters);//任务优先级
#define DATAPROCESS_TASK_PRIO 3  //指令处理函数
//任务堆栈大小	
#define DATAPROCESS_STK_SIZE  256 
//任务句柄
TaskHandle_t DataProcess_Handler;
//任务函数
void DataProcess_task(void *pvParameters);//二值信号量句柄
SemaphoreHandle_t BinarySemaphore;    //二值信号量句柄//用于命令解析用的命令值
#define LED1ON  1
#define LED1OFF 2
#define BEEPON  3
#define BEEPOFF 4
#define COMMANDERR  0xFF//进入低功耗模式前需要处理的事件
//ulExpectedIdleTime:低功耗模式运行时间
void PreSleepProcessing(void)   //因为二值信号量实验用到了串口,所以对GPIOB~H时钟不使能!
{//关闭某些低功耗模式下不使用的外设时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,DISABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,DISABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,DISABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,DISABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,DISABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,DISABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH,DISABLE);
}//退出低功耗模式以后需要处理的事情
//ulExpectedIdleTime:低功耗模式运行时间
void PostSleepProcessing(void)
{//退出低功耗模式以后打开那些被关闭的外设时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH,ENABLE);
}//空闲任务钩子函数
void vApplicationIdleHook(void)
{__disable_irq();__dsb(portSY_FULL_READ_WRITE );__isb(portSY_FULL_READ_WRITE );PreSleepProcessing();		//进入睡眠模式之前需要处理的事情__wfi();				    //进入睡眠模式PostSleepProcessing();		//退出睡眠模式之后需要处理的事情__dsb(portSY_FULL_READ_WRITE );__isb(portSY_FULL_READ_WRITE );__enable_irq();
}//函数 LowerToCap 用于将串口发送过来的命令中的小写字母统一转换成大写字母,
//这样就可以在发送命令的时候不用区分大小写,因为开发板会统一转换成大写。
//将字符串中的小写字母转换为大写
//str:要转换的字符串
//len:字符串长度
void LowerToCap(u8 *str,u8 len)
{u8 i;for(i=0;i<len;i++){//判断字符串的ASCII码是否位于96到123之间if((96<str[i])&&(str[i]<123))  //小写字母{//ASCII码是一种用于表示字符的编码系统。在ASCII码中,每个字符都被赋予一个唯一的整数值。//大写字母的ASCII码值是65到90//小写字母的ASCII码值是97到122   所以一旦确定ASCII码值位于小写字母的范畴内,只需要将ASCII码值减去32即可转换为大写str[i] = str[i] - 32;  //转换为大写}}
}//函数 CommandProcess 用于将接收到的命令字符串转换成命令值,比如说命令“LED1ON”转换成命令值就是 0(宏LED1ON为 0)
//命令处理函数,将字符串命令转换成命令值
//str:命令
//返回值:0xFF,命令错误;其他值,命令值
u8 CommandProcess(u8 *str)
{u8 CommandValue = COMMANDERR;if(strcmp((char*)str,"LED1ON")==0) //strcmp 字符串比较函数//这个函数会比较两个参数;比较时,会以字符的ASCII值进行比较//如果str1的ASCII码值小于str2,返回一个负数;反之,返回一个正数;//如果str1的ASCII码值等于str2,返回 0,此时,if判断语句成立CommandValue = LED1ON; //设置的LED1ON的宏为1,也就是在串口输入1,if判断语句成立else if(strcmp((char*)str,"LED1OFF")==0)CommandValue = LED1OFF; //在串口输入2,if判断语句成立else if(strcmp((char*)str,"BEEPON")==0)CommandValue = BEEPON; //在串口输入3,if判断语句成立else if(strcmp((char*)str,"BEEPOFF")==0)CommandValue = BEEPOFF; //在串口输入4,if判断语句成立return CommandValue;
}int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); //设置系统中断优先级delay_init(168);uart_init(115200);LED_Init();KEY_Init();BEEP_Init();LCD_Init();my_mem_init(SRAMIN);    //初始化内部内存池POINT_COLOR=RED;LCD_ShowString(10,10,200,16,16,"ATK STM32F407");LCD_ShowString(10,30,200,16,16,"FreeRTOS Example");LCD_ShowString(10,50,200,16,16,"Binary Semaphore");LCD_ShowString(10,70,200,16,16,"Command Data:");//创建开始任务xTaskCreate((TaskFunction_t )start_task,            //任务函数(const char*    )"start_task",          //任务名称(uint16_t       )START_STK_SIZE,        //任务堆栈大小(void*          )NULL,                  //传递给任务函数的参数(UBaseType_t    )START_TASK_PRIO,       //任务优先级(TaskHandle_t*  )&StartTask_Handler);   //任务句柄              vTaskStartScheduler();          //开启任务调度
}//开始任务任务函数
void start_task(void *pvParameters)
{taskENTER_CRITICAL();    //进入临界区//创建二值信号量,也就是创建一个长度为1的队列BinarySemaphore = xSemaphoreCreateBinary();   //xSemaphoreCreateBinary函数为动态创建二值信号量函数//返回 NULL,二值信号量创建失败;返回其他值,表示创建成功的二值信号量的句柄;//所以BinarySemaphore表示创建成功的二值信号量的句柄;//创建Task1任务xTaskCreate((TaskFunction_t )task1_task,            //任务函数(const char*    )"task1_task",          //任务名称(uint16_t       )TASK1_STK_SIZE,        //任务堆栈大小(void*          )NULL,                  //传递给任务函数的参数(UBaseType_t    )TASK1_TASK_PRIO,       //任务优先级(TaskHandle_t*  )&Task1Task_Handler);   //任务句柄  //创建Task2任务xTaskCreate((TaskFunction_t )DataProcess_task,            //任务函数(const char*    )"DataProcess_task",          //任务名称(uint16_t       )DATAPROCESS_STK_SIZE,        //任务堆栈大小(void*          )NULL,                  //传递给任务函数的参数(UBaseType_t    )DATAPROCESS_TASK_PRIO,       //任务优先级(TaskHandle_t*  )&DataProcess_Handler);   //任务句柄  vTaskDelete(StartTask_Handler);  //删除开始任务taskEXIT_CRITICAL();          //退出临界区
}//Task1任务
//控制 LED0 闪烁,提示系统正在运行
void task1_task(void *pvParameters)
{while(1){LED0=!LED0;vTaskDelay(500);        //延时500ms,也就是500个时钟节拍}
}//DataProcess_task函数
//指令处理任务,根据接收到的指令来控制不同的外设
void DataProcess_task(void *pvParameters)
{u8 len=0;u8 CommandValue=COMMANDERR;BaseType_t err=pdFALSE;u8 *CommandStr;while(1){err=xSemaphoreTake(BinarySemaphore,portMAX_DELAY); //获取信号量函数;返回值pdTURE,获取信号量成功;pdFALSE,获取信号量失败;//第一个参数,要获取的信号量句柄//第二个参数,阻塞时间,这里设置为portMAX_DEALY,译为无限等待,直至获得信号量if(err==pdTRUE) //获取信号量成功{len=USART_RX_STA&0x3fff;  //得到此次接收到的数据长度//接收状态//bit15,	接收完成标志//bit14,	接收到0x0d//bit13~0,	接收到的有效字节数目CommandStr=mymalloc(SRAMIN,len+1);  //申请内存 指针指向申请内存的首地址sprintf((char*)CommandStr,"%s",USART_RX_BUF);  //打印接收缓存区,把接收缓存区的数据保存到CommandStr中CommandStr[len]='\0';   //加上字符串结尾符号//CommandStr 是个指针,长度为len,数组是从下角标 0 开始的,所以len就表示数组的最后一个LowerToCap(CommandStr,len);  //将字符串转换成大写CommandValue=CommandProcess(CommandStr);  //命令解析,也就是获取上面定义的宏 1 2 3 4if(CommandValue!=COMMANDERR)//if判断语句成立,表示CommandValue不等于0xFF,那也就是 LED1ON、LED1OFF、BEEPON、BEEPOFF 其中一个指令{printf("命令为:%s\r\n",CommandStr);   switch(CommandValue){case LED1ON:LED1=0;break;case LED1OFF:LED1=1;break;case BEEPON:BEEP=1;break;case BEEPOFF:BEEP=0;break;}}else{//当命令错误的时候开发板会向串口调试助手发送命令错误的提示信息//比如我们发送 LED1_off 这个命令,串口助手会显示:无效的命令,请重新输入!!printf("无效的命令,请重新输入!!\r\n");}USART_RX_STA = 0;memset(USART_RX_BUF,0,USART_REC_LEN);  //串口接收缓冲区清零myfree(SRAMIN,CommandStr);             //释放内存}}
}

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

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

相关文章

广东开放大学:电大搜题助力学子迎考利器

近年来&#xff0c;广东开放大学一直致力于为广大学子提供优质的教育资源和学习服务。作为一所专注于远程教育的学府&#xff0c;广东开放大学不仅拥有雄厚的师资力量和丰富的教育经验&#xff0c;还致力于创新教学手段&#xff0c;为学生提供更便捷、高效的学习体验。在这个信…

2023年11月在线IDE流行度最新排名

点击查看最新在线IDE流行度最新排名&#xff08;每月更新&#xff09; 2023年11月在线IDE流行度最新排名 TOP 在线IDE排名是通过分析在线ide名称在谷歌上被搜索的频率而创建的 在线IDE被搜索的次数越多&#xff0c;人们就会认为它越受欢迎。原始数据来自谷歌Trends 如果您相…

08.Diffusion Model数学原理分析(上)

文章目录 Diffusion Model回顾Diffusion Model算法TrainingInference 图像生成模型的本质目标MLE vs KLVAE计算 P θ ( x ) P_\theta(x) Pθ​(x)Lower bound of log ⁡ P ( x ) \log P(x) logP(x) DDPM计算 P θ ( x ) P_\theta(x) Pθ​(x)Lower bound of log ⁡ P ( x ) \…

数据结构与算法-(11)---有序表(OrderedList)

&#x1f308;个人主页: Aileen_0v0 &#x1f525;系列专栏:PYTHON学习系列专栏 &#x1f4ab;"没有罗马,那就自己创造罗马~" 目录 知识回顾及总结 有序表的引入 ​编辑 实现有序表 1.有序表-类的构造方法 2.有序表-search方法的实现 3.有序表-add方法的实现…

【技术类-01】doc转PDF程序卡死的解决方案,

摘要&#xff1a; 1、出现 raise AttributeError("%s.%s" % (self._username_, attr))&#xff09; 2、表现&#xff1a;doc转PDF卡死&#xff08;白条不动或出现以上英文&#xff09; 3、解决&#xff1a;在docx保存代码行后面加上time.sleep(3) 4、原因&#x…

SpringBoot系列之集成Redission入门与实践教程

Redisson是一款基于java开发的开源项目&#xff0c;提供了很多企业级实践&#xff0c;比如分布式锁、消息队列、异步执行等功能。本文基于Springboot2版本集成redisson-spring-boot-starter实现redisson的基本应用 软件环境&#xff1a; JDK 1.8 SpringBoot 2.2.1 Maven 3.2…

Java进阶篇--线程池之FutureTask

目录 FutureTask简介 FutureTask的基本使用 FutureTask的应用场景 FutureTask简介 FutureTask是Java中的一个类&#xff0c;用于表示可获取结果的异步任务。它实现了java.util.concurrent.Future接口&#xff0c;提供了启动和取消异步任务、查询任务是否已完成以及获取最终…

腾讯云3年云服务器价格及购买教程

腾讯云作为国内领先的云计算服务提供商&#xff0c;提供了多种优惠的云服务器套餐&#xff0c;以满足不同用户的需求&#xff0c;本文将详细介绍腾讯云3年云服务器价格及购买教程&#xff0c;新老用户均可购买&#xff01; 1、活动页面&#xff1a;传送门>>> 2、进入…

P3379 【模板】最近公共祖先(LCA)

洛谷里面8页题解千篇一律&#xff0c;就没有用线段树求解的&#xff0c;这下不得不由本蒟蒻来生啃又臭又硬&#xff0c;代码又多的线段树了。 样例的欧拉序列&#xff1a;4 2 4 1 3 1 5 1 4 记录每个节点最早在欧拉序列中的时间&#xff0c;任意两个节点的LCA就是他们两个节点…

Flink -- 状态与容错

1、Stateful Operations 有状态算子&#xff1a; 有状态计算&#xff0c;使用到前面的数据&#xff0c;常见的有状态的算子&#xff1a;例如sum、reduce&#xff0c;因为它们在计算的时候都是用到了前面的计算的结果 总结来说&#xff0c;有状态计算并不是独立存在的&#xf…

ssh免密登录

单机 1 生成密钥 执行 ssh-keygen -t rsa &#xff08; 其中 rsa 是非对称算法&#xff09; 一路回车到底&#xff0c;生成密钥 且生成之后会在用户的根目录生成一个 “.ssh”的文件夹 2 添加公钥到 将 公钥内容追加到 authorized_keys 中&#xff1a; cat ~/.ssh/id_rsa.pub …

汽车网络安全渗透测试概述

目录 1.汽车网络安全法规概述 1.1 国外标准 1.2 国内标准 2.汽车网络安全威胁分析 2.1 汽车网络安全资产定义 2.2 汽车网络安全影响场景及评级示例 3.汽车网络安全渗透测试描述 3.1 参考法规 3.2 渗透测试内容 4.小结 1.汽车网络安全法规概述 近年来&#xff0c;汽车…

科技创意赋能乡村文旅振兴

近日&#xff0c;由北京大学创意产业研究中心联合中国国际科技促进会新基建专委会共同主办的“科技创意赋能乡村振兴研讨会”在京举行&#xff0c;与会专家学者围绕“和美乡村共同富裕智慧文旅”主题进行深入探讨。北京大学创意产业研究中心副主任吕艺、国家文化和旅游公共服务…

Android UI 开发·界面布局开发·案例分析

目录 ​编辑 1. 线性布局&#xff08;LinearLayout&#xff09; 2. 相对布局&#xff08;RelativeLayout&#xff09; 3. 表格布局&#xff08;TableLayout&#xff09; 4. 帧布局&#xff08;FrameLayout&#xff09; 5. 网格布局&#xff08;GridLayout&#xff0…

Linux 学习(CentOS 7)

CentOS 7 学习 Linux系统内核作者: Linux内核版本 内核(kernel)是系统的心脏&#xff0c;是运行程序和管理像磁盘和打印机等硬件设备的核心程序&#xff0c;它提供了一个在裸设备与应用程序间的抽象层。 Linux内核版本又分为稳定版和开发版&#xff0c;两种版本是相互关联&am…

【小白专用】VSCode下载和安装与配置PHP开发环境(详细版) 23.11.08

1. 下载VSCode2. 解决VSCode下载速度特别慢3. 安装VSCode 一、VSCode介绍 VSCode 是一款由微软开发且跨平台的免费源代码编辑器&#xff1b;该软件支持语法高亮、代码自动补全、代码重构、查看定义功能&#xff0c;并且内置了命令行工具和 Git 版本控制系统。 二、官方下载地址…

网络带宽基础知识简单介绍

网络带宽基础知识简单介绍 前言一、网络带宽是什么&#xff1f;二、影响网络带宽的因素三、网络带宽的单位总结 前言 最近一些需求涉及到了网络带宽&#xff0c;整理后有了本文 一、网络带宽是什么&#xff1f; 网络带宽是指在单位时间内&#xff08;一般指的是1秒钟&#xf…

django+drf+vue 简单系统搭建 (1) - django创建项目

本系列文章为了记录自己第一个系统生成过程&#xff0c;主要使用django,drf,vue。本人非专业人士&#xff0c;此文只为记录学习&#xff0c;若有部分描述不够准确的地方&#xff0c;烦请指正。 建立这个系统的原因是因为&#xff0c;在生活中&#xff0c;很多觉得可以一两行代码…

Flutter的专属Skia引擎解析+用法原理

Skia是一款跨平台的2D图形库&#xff0c;是Google公司开发的&#xff0c;可以用于开发各种应用程序&#xff0c;如浏览器、游戏、移动应用程序等。Skia引擎的主要特点是速度快、可移植性强、占用的内存少、稳定性佳&#xff0c;适用于多种硬件平台。 Skia的目标是提供快速、高…

基于GCC的工具objdump实现反汇编

一&#xff1a;objdump介绍 在 Linux中&#xff0c;一切皆文件。 Linux 编程实际上是编写处理各种文件的代码。系统由许多类型的文件组成&#xff0c;但目标文件具有一种特殊的设计&#xff0c;提供了灵活和多样的用途。 目标文件是包含带有附加地址和值的助记符号的路线图。这…