FreeRTOS任务管理

 1. 任务状态理论讲解

 定时器职中断周期此处的1000Hz表示的是没次间隔1毫秒就记一次数(在FreeConfig.h)文件中进行配置

#define configTICK_RATE_HZ			( ( TickType_t ) 1000 )

判断是否需要任务切换在FreeRTOS里面每次间隔1毫秒切换一次(程序辅助理解图如下所示)

 FreeRTOS中三种状态的切换(分别是就绪态,阻塞态,暂停态),三种状态的理解图如下说所示

2. 任务状态实验

对应程序:08_freertos_example_task_status

  • 任务切换的基础:tick中断

  • 有哪些任务状态?状态切换图

  • 怎么管理不同状态的任务:放在不同链表里

  • 阻塞状态(Blocked)举例:vTaskDelay函数

  • 暂停状态(Suspended)举例:vTaskSuspend/vTaskResume

任务状态理解图展示

程序测试过程中遇到的问题

Load "F:\\STM32Study\\FreeRTOS_WDS\\1-6freertos_example_createtaskstatic\\FreeRTOS\\Demo\\CORTEX_STM32F103_Keil\\RTOSDemo.axf" 
BS \\RTOSDemo\main.c\200, 1
WS 1, `ch
LA `task1flagrun
___^
*** error 34: undefined identifier
LA `task2flagrun
___^
*** error 34: undefined identifier
LA `task3flagrun
___^
*** error 34: undefined identifier
*** error 65: access violation at 0x4002100C : no 'write' permission
*** error 65: access violation at 0x40021010 : no 'write' permission

解决问题参考文章

Keil Debug——*** error 65: access violation at 0x20005000 : no ‘write‘ permission_*** error 65: access violation at 0x4002100c : no -CSDN博客文章浏览阅读840次,点赞2次,收藏5次。当遇到"*** error 65: access violation at 0x20005000 : no 'write' permission"类似错误时,这通常表示程序试图写入一个没有写入权限的内存地址。这个错误可能有多种原因,以下是一些常见的解决方法:1. 检查内存保护设置:请确保您的程序没有试图写入受保护的内存区域。某些嵌入式系统可能使用内存保护机制,如存储器保护单元(MPU)或写保护寄存器。请检查您的系统文档或参考手册,了解如何正确配置内存保护设置。_*** error 65: access violation at 0x4002100c : no 'write' permissionhttps://blog.csdn.net/weixin_44406127/article/details/134159125

具体修改方式如下所示

测试代码

// 定义一个全局标记为用于表示任务是否在运行
static int task1flagrun = 0;
static int task2flagrun = 0;
static int task3flagrun = 0;TaskHandle_t xHandleTask1;   // 任务1的句柄
TaskHandle_t xHandleTask2;   // 任务2的句柄
TaskHandle_t xHandleTask3;   // 任务3的句柄void Task1Function(void * pram){// 获取TickCount的函数TickType_t tStart = xTaskGetTickCount();TickType_t t;// 添加标记位int flag  = 0;while(1){t = xTaskGetTickCount();task1flagrun = 1;task2flagrun = 0;task3flagrun = 0;printf("1"); if(!flag && (t > tStart + 10)){vTaskSuspend(xHandleTask3);   // 命令任务3进入暂停状态flag = 1;}if(t > tStart + 20){vTaskResume(xHandleTask3);    // 调用Resume进入就绪状态}}
}void Task2Function(void * pram){int i = 0;while(1){task1flagrun = 0;task2flagrun = 1;task3flagrun = 0;printf("2");// 让任务2进入到阻塞状态vTaskDelay(10);  // 这个是系统的延迟函数,主动进入阻塞状态,// 等待某个时刻的到来,这个时刻就是当前时间加上10个tick}
}void Task3Function(void * pram){while(1){task1flagrun = 0;task2flagrun = 0;task3flagrun = 1;printf("3");}
}void TaskGenericFunction(void * pram){int val = (int) pram;while(1){task1flagrun = 0;task2flagrun = 0;task3flagrun = 1;printf("%d",val);}
}StackType_t xTask3Stack[100];
StaticTask_t xTask3TCB;
// 创建空闲的任务(创建静态任务的时候要编写一个函数让CPU在空闲的状态下也不能闲着)
StackType_t xIdleTaskStack[100];
StaticTask_t xIdleTaskTCB;// 提供空闲栈的大小
void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,StackType_t ** ppxIdleTaskStackBuffer,uint32_t * pulIdleTaskStackSize
){*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;*ppxIdleTaskStackBuffer = xIdleTaskStack;*pulIdleTaskStackSize = 100;
}int main( void )
{#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");xTaskCreate(Task1Function,"Task1",100,NULL,1,&xHandleTask1);xTaskCreate(Task2Function,"Task2",100,NULL,1,NULL);xHandleTask3 = xTaskCreateStatic(Task3Function,"task3",100,NULL,1,xTask3Stack,&xTask3TCB);vTaskStartScheduler();/* Will only get here if there was not enough heap space to create theidle task. */return 0;
}

 测试程序PWM波形图

3. vTaskDelay和vTaskDelayUntil原理用法

对应程序:09_freertos_example_delay

有两个Delay函数:

  • vTaskDelay:至少等待指定个数的Tick Interrupt才能变为就绪状态

  • vTaskDelayUntil

    • 老版本,没有返回值

    • 等待到指定的绝对时刻,才能变为就绪态。

  • xTaskDelayUntil

    • 新版本,返回pdTRUE表示确实延迟了,返回pdFALSE表示没有发生延迟(因为延迟的时间点早就过了)

    • 等待到指定的绝对时刻,才能变为就绪态。

遇到这个问题:遇到不恰当的争论

 这个问题的原因是在keil结束断点调试的时候没有吧断点取消掉,然后就会一直报这个错误,并且KEIL无法关闭,调试完程序后一定要吧keil关闭掉

代码测试过程中遇到的问题

解决问题的博客:解决调试时候出现的“Encountered an improper argument”错误-CSDN博客文章浏览阅读2.6w次,点赞23次,收藏30次。今天分享一个我们在调试时候出现的一个错误,同时这个错误让我的工程也崩了好几十次。_encountered an improper argumenthttps://blog.csdn.net/OMGMac/article/details/126614887

测试程序的代码

 

// 定义一个全局标记为用于表示任务是否在运行
static int task1flagrun = 0;
static int task2flagrun = 0;
static int task3flagrun = 0;static int rands[] = {10,3,6,8,9,99,66};TaskHandle_t xHandleTask1;   // 任务1的句柄
TaskHandle_t xHandleTask2;   // 任务2的句柄
TaskHandle_t xHandleTask3;   // 任务3的句柄void Task1Function(void * pram){// 获取TickCount的函数TickType_t tStart = xTaskGetTickCount();int i = 0;int j = 0;while(1){task1flagrun = 1;task2flagrun = 0;task3flagrun = 0;// 延时函数执行的时间是不固定的for(i = 0; i <rands[j]; i++){printf("1"); 	}j++;if(j == 7){j = 0;}vTaskDelay(20);	}
}void Task2Function(void * pram){int i = 0;while(1){task1flagrun = 0;task2flagrun = 1;task3flagrun = 0;printf("2");}
}void Task3Function(void * pram){while(1){task1flagrun = 0;task2flagrun = 0;task3flagrun = 1;printf("3");}
}void TaskGenericFunction(void * pram){int val = (int) pram;while(1){task1flagrun = 0;task2flagrun = 0;task3flagrun = 1;printf("%d",val);}
}StackType_t xTask3Stack[100];
StaticTask_t xTask3TCB;
// 创建空闲的任务(创建静态任务的时候要编写一个函数让CPU在空闲的状态下也不能闲着)
StackType_t xIdleTaskStack[100];
StaticTask_t xIdleTaskTCB;// 提供空闲栈的大小
void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,StackType_t ** ppxIdleTaskStackBuffer,uint32_t * pulIdleTaskStackSize
){*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;*ppxIdleTaskStackBuffer = xIdleTaskStack;*pulIdleTaskStackSize = 100;
}int main( void )
{#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");xTaskCreate(Task1Function,"Task1",100,NULL,2,&xHandleTask1);xTaskCreate(Task2Function,"Task2",100,NULL,1,NULL);xHandleTask3 = xTaskCreateStatic(Task3Function,"task3",100,NULL,1,xTask3Stack,&xTask3TCB);vTaskStartScheduler();/* Will only get here if there was not enough heap space to create theidle task. */return 0;
}

编写代码后程序的执行结果展示:PWM波形结果展示vTaskDelay()这个函数可以保证休眠的时间是一样的但是无法保证程序执行的时刻间隔是一样的

vTaskDelayUntil函数的含义

测试代码

// 定义一个全局标记为用于表示任务是否在运行
static int task1flagrun = 0;
static int task2flagrun = 0;
static int task3flagrun = 0;static int rands[] = {10,3,6,8,9,99,66};TaskHandle_t xHandleTask1;   // 任务1的句柄
TaskHandle_t xHandleTask2;   // 任务2的句柄
TaskHandle_t xHandleTask3;   // 任务3的句柄void Task1Function(void * pram){// 获取TickCount的函数,表示将启动的时间记录下来TickType_t tStart = xTaskGetTickCount();int i = 0;int j = 0;while(1){task1flagrun = 1;task2flagrun = 0;task3flagrun = 0;// 延时函数执行的时间是不固定的for(i = 0; i <rands[j]; i++){printf("1"); 	}j++;if(j == 7){j = 0;}
#if 0 vTaskDelay(20);	
#elsevTaskDelayUntil(&tStart,20);
#endif}
}void Task2Function(void * pram){int i = 0;while(1){task1flagrun = 0;task2flagrun = 1;task3flagrun = 0;printf("2");}
}void Task3Function(void * pram){while(1){task1flagrun = 0;task2flagrun = 0;task3flagrun = 1;printf("3");}
}void TaskGenericFunction(void * pram){int val = (int) pram;while(1){task1flagrun = 0;task2flagrun = 0;task3flagrun = 1;printf("%d",val);}
}StackType_t xTask3Stack[100];
StaticTask_t xTask3TCB;
// 创建空闲的任务(创建静态任务的时候要编写一个函数让CPU在空闲的状态下也不能闲着)
StackType_t xIdleTaskStack[100];
StaticTask_t xIdleTaskTCB;// 提供空闲栈的大小
void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,StackType_t ** ppxIdleTaskStackBuffer,uint32_t * pulIdleTaskStackSize
){*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;*ppxIdleTaskStackBuffer = xIdleTaskStack;*pulIdleTaskStackSize = 100;
}int main( void )
{#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");xTaskCreate(Task1Function,"Task1",100,NULL,2,&xHandleTask1);xTaskCreate(Task2Function,"Task2",100,NULL,1,NULL);xHandleTask3 = xTaskCreateStatic(Task3Function,"task3",100,NULL,1,xTask3Stack,&xTask3TCB);vTaskStartScheduler();/* Will only get here if there was not enough heap space to create theidle task. */return 0;
}

PWM波形展示

4. 空闲任务及其钩子函数

对应程序:10_freertos_example_idletask,在05_freertos_example_createtask基础上修改

  • 任务后的清理工作在哪执行?分两类:

    • 自杀的任务:在空闲任务中完成清理工作,比如释放内存(都自杀了,怎么清理自己的尸体? 由别人来做)

    • 非自杀的任务:在vTaskDelete内部完成清理工作(凶手执行清理工作)

  • 空闲任务何时才能执行?

  • 空闲任务只能处于这2个状态之一:Running、Ready

  • 空闲任务钩子函数

    • 执行一些低优先级的、后台的、需要连续执行的函数

    • 测量系统的空闲时间:空闲任务能被执行就意味着所有的高优先级任务都停止了,所以测量空闲任 务占据的时间,就可以算出处理器占用率。

    • 让系统进入省电模式:空闲任务能被执行就意味着没有重要的事情要做,当然可以进入省电模式 了。

    • 绝对不能导致任务进入Blocked、Suspended状态

    • 如果你会使用 vTaskDelete() 来删除任务,那么钩子函数要非常高效地执行。如果空闲任务移植 卡在钩子函数里的话,它就无法释放内存。

空闲任务和钩子函数

定时宏:实现函数(这个钩子函数有一定的限制就是不能让空闲的任务进入空闲的状态或者是阻塞的状态要让空闲的任务执行一些清理的状态,因此空闲的任务要么处于运行状态,要么处于就绪状态永远不能处于阻塞状态,钩子函数执行的速度要越快越好)

实现代码

void Task2Function(void * param);// 这个是任务的标志位
static int task1flagrun = 0;
static int task2flagrun = 0;
static int taskidleflagrun = 0;// 在主函数中创建任务1,在任务1里面创建任务2,并在任务1中删除任务2
void Task1Function(void * param)
{TaskHandle_t xHandleTask2;BaseType_t xReturn;while (1){// 在任务1里面设置对应的变量task1flagrun = 1;task2flagrun = 0;taskidleflagrun = 0;printf("1");// 保存这个函数的返回值xReturn = xTaskCreate(Task2Function, "Task2", 1024, NULL, 2, &xHandleTask2);// 判断如果等于pass的话表示返回成功if (xReturn != pdPASS)printf("xTaskCreate err\r\n");//vTaskDelete(xHandleTask2);}
}void Task2Function(void * param)
{while (1){// 在任务2里面设置自己对应的变量task1flagrun = 0;task2flagrun = 1;taskidleflagrun = 0;printf("2");   // 观察变量的高低电平//vTaskDelay(2);vTaskDelete(NULL);}
}// 这个是任务调度函数:也就是钩子函数
void vApplicationIdleHook( void )
{task1flagrun = 0;task2flagrun = 0;taskidleflagrun = 1;	printf("0");
}/*-----------------------------------------------------------*/int main( void )
{TaskHandle_t xHandleTask1;#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");// 设置任务1的优先级将任务1的优先级设置为0xTaskCreate(Task1Function, "Task1", 100, NULL, 0, &xHandleTask1);/* Start the scheduler. */vTaskStartScheduler();/* Will only get here if there was not enough heap space to create theidle task. */return 0;
}

实现函数(钩子函数不能放在死循环中不然空闲任务就不能执行其他的操作比如清理工作)

5. 任务调度算法

正在运行的任务,被称为"正在使用处理器",它处于运行状态。在单处理器系统中,任何时间里只能有一个任务处于运行状态。

非运行状态的任务,它处于这3种状态之一:

  • 阻塞(Blocked)

  • 暂停(Suspended)

  • 就绪(Ready)

就绪态的任务,可以被调度器挑选出来切换为运行状态,调度器永远都是挑选最高优先级的就绪态任务并让它进入运行状态。

阻塞状态的任务,它在等待"事件",当事件发生时任务就会进入就绪状态。

事件分为两类:

  • 时间相关的事件

    • 所谓时间相关的事件,就是设置超时时间:在指定时间内阻塞,时间到了就进入就绪状态。

    • 使用时间相关的事件,可以实现周期性的功能、可以实现超时功能。

  • 同步事件

    • 同步事件就是:某个任务在等待某些信息,别的任务或者中断服务程序会给它发送信息。

    • 怎么"发送信息"?方法很多

      • 任务通知(task notification)

      • 队列(queue)

      • 事件组(event group)

      • 信号量(semaphoe)

      • 互斥量(mutex)等

      • 这些方法用来发送同步信息,比如表示某个外设得到了数据。

static void prvSetupHardware( void );static volatile int flagIdleTaskrun = 0;  // 空闲任务运行时flagIdleTaskrun=1
static volatile int flagTask1run = 0;     // 任务1运行时flagTask1run=1
static volatile int flagTask2run = 0;     // 任务2运行时flagTask2run=1
static volatile int flagTask3run = 0;     // 任务3运行时flagTask3run=1/*-----------------------------------------------------------*/void vTask1( void *pvParameters )
{/* 任务函数的主体一般都是无限循环 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 1;flagTask2run = 0;flagTask3run = 0;/* 打印任务的信息 */printf("T1\r\n");				}
}void vTask2( void *pvParameters )
{	/* 任务函数的主体一般都是无限循环 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 0;flagTask2run = 1;flagTask3run = 0;/* 打印任务的信息 */printf("T2\r\n");				}
}void vTask3( void *pvParameters )
{	const TickType_t xDelay5ms = pdMS_TO_TICKS( 5UL );		/* 任务函数的主体一般都是无限循环 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 0;flagTask2run = 0;flagTask3run = 1;/* 打印任务的信息 */printf("T3\r\n");				// 如果不休眠的话, 其他任务无法得到执行vTaskDelay( xDelay5ms );}
}void vApplicationIdleHook(void)
{flagIdleTaskrun = 1;flagTask1run = 0;flagTask2run = 0;flagTask3run = 0;	/* 故意加入打印让flagIdleTaskrun变为1的时间维持长一点 *///printf("Id\r\n");				
}int main( void )
{prvSetupHardware();//动态创建任务1优先级是0xTaskCreate(vTask1, "Task 1", 1000, NULL, 0, NULL);//动态创建任务2优先级是0xTaskCreate(vTask2, "Task 2", 1000, NULL, 0, NULL);//动态创建任务3优先级是2xTaskCreate(vTask3, "Task 3", 1000, NULL, 2, NULL);/* 启动调度器 */vTaskStartScheduler();/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}

此处的高优先级的先执行

 

以下是任务调度相关部分的代码

/* Demo app includes. */
static void prvSetupHardware( void );static volatile int flagIdleTaskrun = 0;  // 空闲任务运行时flagIdleTaskrun=1
static volatile int flagTask1run = 0;     // 任务1运行时flagTask1run=1
static volatile int flagTask2run = 0;     // 任务2运行时flagTask2run=1
static volatile int flagTask3run = 0;     // 任务3运行时flagTask3run=1/*-----------------------------------------------------------*/void vTask1( void *pvParameters )
{/* 任务函数的主体一般都是无限循环 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 1;flagTask2run = 0;flagTask3run = 0;/* 打印任务的信息 */printf("T1\r\n");				}
}void vTask2( void *pvParameters )
{	/* 任务函数的主体一般都是无限循环 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 0;flagTask2run = 1;flagTask3run = 0;/* 打印任务的信息 */printf("T2\r\n");				}
}void vTask3( void *pvParameters )
{	const TickType_t xDelay5ms = pdMS_TO_TICKS( 5UL );		/* 任务函数的主体一般都是无限循环 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 0;flagTask2run = 0;flagTask3run = 1;/* 打印任务的信息 */printf("T3\r\n");				// 如果不休眠的话, 其他任务无法得到执行vTaskDelay( xDelay5ms );}
}void vApplicationIdleHook(void)
{flagIdleTaskrun = 1;flagTask1run = 0;flagTask2run = 0;flagTask3run = 0;	/* 故意加入打印让flagIdleTaskrun变为1的时间维持长一点 *///printf("Id\r\n");				
}int main( void )
{prvSetupHardware();//动态创建任务1优先级是0xTaskCreate(vTask1, "Task 1", 1000, NULL, 0, NULL);//动态创建任务2优先级是0xTaskCreate(vTask2, "Task 2", 1000, NULL, 0, NULL);//动态创建任务3优先级是2xTaskCreate(vTask3, "Task 3", 1000, NULL, 2, NULL);/* 启动调度器 */vTaskStartScheduler();/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}

这种调度策略表示的是不允许抢占,(使用这种方式编写代码最好是在做完一些事情之后放弃占用CPU的资源)

 

#define configUSE_PREEMPTION 1  是否支持抢占式调度 #define configUSE_TIME_SLICING 1              时间片轮转(默认的情况下应该是支持时间片轮转的)

这个是是否支持时间片轮转的的任务函数(PWM)波形

#define configIDLE_SHOULD_YIELD 1 这个表示的是空闲的任务应该空闲礼让他人,将GPU资源让给用户任务

这个是是否空闲任务礼让其他的CPU任务的PWM波形

这个是礼让(空闲的任务礼让其他的任务)

这个是不礼让(空闲的任务不礼让,也其他的任务一样抢占CPU的资源)

5.2 调度策略

  • 是否抢占?

  • #define configUSE_PREEMPTION 1 是否支持抢占式调度

  • 允许抢占时,是否允许时间片轮转?

  • #define configUSE_TIME_SLICING 1 时间片轮转(默认的情况下应该是支持时间片轮转的)

  • 允许抢占、允许时间片轮转时,空闲任务是否让步?

  • #define configIDLE_SHOULD_YIELD 1 这个表示的是空闲的任务应该空闲礼让他人,将GPU资源让给用户任务

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

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

相关文章

【iOS开发】(二)react Native基础语法+样式+布局20240417

【IOS开发】 前言&#xff1a;&#xff08;一&#xff09;我们已经搭建好了基础环境&#xff0c;和iOS环境&#xff0c;并创建和在模拟器上成功运行了一个app&#xff0c;mywdm。 目录标题 一&#xff0c; 如何进行模拟器调试二&#xff0c;基础语法&#xff1a;1 掌握reactjs…

网站创建的流程是什么

网站的创建过程包括几个主要的步骤&#xff0c;其中涉及到一系列的决策和实践操作。下面我将详细介绍网站创建的流程&#xff0c;帮助读者了解如何创建一个成功的网站。 第一步&#xff1a;确定网站目标和功能 在创建网站之前&#xff0c;你需要明确自己网站的目标和功能。是用…

AT32F415CBT7 封装LQFP-48 单片机微控制器IC芯片

ARM Cortex-M4 内核&#xff1a;AT32F415CBT7 采用 32 位 ARM Cortex-M4 内核&#xff0c;工作频率高达 200 MHz&#xff0c;具有较高的处理能力和响应速度。 大容量闪存存储器&#xff1a;该单片机内置 256KB 的闪存存储器&#xff08;Flash&#xff09;&#xff0c;可以存储…

Hadoop中的MapReduce流程(图解)

一、MapReduce流程图&#xff1a; 二、MapReduce流程步骤&#xff1a; 1.文件上传到HDFS中&#xff0c;默认以128M切分为一个block块 2.每个block块对数据进行逻辑上的切片&#xff0c;切片大小为128M,与block块大小一致 3.之后根据切片产生Map任务 4.Map任务会进入环形缓冲区&…

Linux 操作系统指令和Vscdoe安装

1、Linux系统介绍 Linux系统的背景介绍我就不介绍了&#xff0c;有兴趣的可以去看看其发展史。 1.1 Linux操作系统的主要特点 Linux操作系统的重要思想&#xff1a;一切皆文件 Linux操作系统的特性&#xff1a; 完全免费 支持多平台 支持多用户、多任务 有良好的界面 完美兼容…

引导过程与故障修复

一、Linux操作系统引导过程 1、引导过程总览 开机自检 检查硬件设备&#xff0c;检测出第一个能够引导系统的设备&#xff0c;比如硬盘或者光驱 MBR 引导 运行MBR扇区里的主引导程序GRUB 启动GRUB菜单 统读取GRUB配置文件(/boot/grub2/grub.cfg)获取内核的设置和位置&#xf…

如何进行数据库的迁移与同步——【DBA 从入门到实践】第四期

在日常的数据库运维工作中&#xff0c;我们时常会面临数据库替换、机房搬迁、业务测试以及数据库升级等任务&#xff0c;这些任务都需要对数据进行迁移和同步操作。【DBA 从入门到实践】第4期&#xff0c;将引导大家深入了解数据库迁移的流程&#xff0c;并探讨在迁移过程中可用…

CTFHUB RCE作业

题目地址&#xff1a;CTFHub 完成情况如图&#xff1a; 知识点&#xff1a; preg_match_all 函数 正则匹配函数 int preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags PREG_PATTERN_ORDER [, int $offset 0 ]]] )搜索 subject 中…

Django第三方功能的使用

Django第三方功能的使用 Django REST framework前言1、Django--Restframework--coreapi版文档BUG:AssertionError: coreapi must be installed for schema support.How to run Django with Uvicorn webserver?2、序列化类 Serializer的使用模型序列化类 ModelSerializer的使用…

linux 安装openjdk-1.8

安装命令 yum install java-1.8.0-openjdk-1.8.0.262.b10-1.el7.x86_64查看安装路径 find / -name java 默认的安装路径 /usr/lib/jvm 查看到jre 以及java-1.8.0-openjdk-1.8.0.262.b10-1.el7.x86_64 配置环境变量 vim /etc/profile 添加的内容 export JAVA_HOME/usr/li…

【面试经典 150 | 二分查找】寻找两个正序数组的中位数

文章目录 写在前面Tag题目来源题目解读方法一&#xff1a;朴素方法二&#xff1a;二分查找【寻找第k小元素】 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附…

[大模型]Qwen-7B-hat Transformers 部署调用

Qwen-7B-hat Transformers 部署调用 环境准备 在autodl平台中租一个3090等24G显存的显卡机器&#xff0c;如下图所示镜像选择PyTorch–>2.0.0–>3.8(ubuntu20.04)–>11.8 接下来打开刚刚租用服务器的JupyterLab&#xff0c;并且打开其中的终端开始环境配置、模型下…

华为机考入门python3--(15)牛客15-求int型正整数在内存中存储时1的个数

分类&#xff1a;二进制 知识点&#xff1a; int转二进制 binary bin(n)[2:] 题目来自【牛客】 def count_ones_in_binary(n): # 将输入的整数转换为二进制字符串 # bin(n)为0b11011binary bin(n)[2:]# 初始化计数器为0 count 0 # 遍历二进制字符串的每一位 fo…

LoRA模型是什么?

AI Agent能力评测工具AgentBench评测结果 LoRA模型是什么&#xff1f; LoRA模型&#xff08;Low-Rank Adaptation of Large Language Models&#xff09;是一种针对大型语言模型&#xff08;LLMs&#xff09;的微调技术&#xff0c;其目的是在保持模型原有性能的基础上&#x…

YOLTV8 — 大尺度图像目标检测框架(欢迎star)

YOLTV8 — 大尺度图像目标检测框架【ABCnutter/YOLTV8: &#x1f680;】 针对大尺度图像&#xff08;如遥感影像、大尺度工业检测图像等&#xff09;&#xff0c;由于设备的限制&#xff0c;无法利用图像直接进行模型训练。将图像裁剪至小尺度进行训练&#xff0c;再将训练结果…

未来课堂革命:OpenAI 发布 ChatGPT 使用指南,探索生成式 AI 如何重塑教育景观

随着新学期的来临&#xff0c;众多初登教师舞台的 00 后们&#xff0c;也完成了他们的第一个教师身份下的暑期生活。 对于开学的抵触情绪&#xff0c;不仅学生们普遍存在&#xff0c;许多 00 后的新晋教师们也同样感同身受。某种程度上&#xff0c;这些抗拒上班的年轻教师群体…

Springboot+Vue项目-基于Java+MySQL的高校心理教育辅导系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

【面试题】MySQL 事务的四大特性说一下?

事务是一个或多个 SQL 语句组成的一个执行单元&#xff0c;这些 SQL 语句要么全部执行成功&#xff0c;要么全部不执行&#xff0c;不会出现部分执行的情况。事务是数据库管理系统执行过程中的一个逻辑单位&#xff0c;由一个有限的数据库操作序列构成。 事务的主要作用是保证数…

金蝶云星空与金蝶云星空对接集成委外超耗查询连通生产订单变更(发顺丰)

金蝶云星空与金蝶云星空对接集成委外超耗查询连通生产订单变更(发顺丰) 对接系统金蝶云星空 金蝶K/3Cloud在总结百万家客户管理最佳实践的基础上&#xff0c;提供了标准的管理模式&#xff1b;通过标准的业务架构&#xff1a;多会计准则、多币别、多地点、多组织、多税制应用框…

FPGA - ZYNQ 基于EMIO的PS和PL交互

前言&#xff1a; Xilinx ZYNQ系列的芯片&#xff0c;GPIO分为 MIO 、EMIO、AXI_GPIO三种方式。 MIO &#xff1a;固定管脚&#xff0c;属于PS端&#xff0c;也就是ARM端。 EMIO &#xff1a;通过PL扩展&#xff0c;使用时需要分配PL(FPGA)管脚&#xff0c;消耗PL端资源。…