05.FreeRTOS任务挂起与恢复

news2024/12/23 9:47:33

05. FreeRTOS任务挂起与任务恢复

1. FreeRTOS 挂起和恢复任务相关 API 函数

函数描述
vTaskSuspend()挂起任务
vTaskResume()恢复被挂起的任务
xTaskResumeFromISR()在中断中恢复被挂起的任务
  1. 函数vTaskSuspend()

    此函数用于挂起任务,若使用此函数,需要在FreeRTOSConfig.h文件中将宏 NCLUDE_vTaskSuspend配置为1。无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复。此函数并不支持嵌套,不论使用此函数重复挂起任务多少次,只需调用一次恢复任务的函数,那么任务就不再被挂起。函数原型如下所示:

    在这里插入图片描述

  2. 函数vTaskResume()

    此函数用于在任务中恢复被挂起的任务,若使用此函数,需要在FreeRTOSConfig.h文件中将宏INCLUDE_VTaskSuspend配置为1。不论一个任务被函数vTaskSuspend()挂起多少次,只需要使用函数vTaskResume()恢复一次,就可以继续运行。函数原型如下所示:

    在这里插入图片描述

  3. 函数xTaskResumeFromISR()

    此函数用于在中断中恢复被挂起的任务,若使用此函数,需要在FreeRTOSConfig.h文件中将宏INCLUDE_xTaskResumeFromISR配置为1。不论一个任务被函数vTaskSuspend()挂起多少次,只需要使用函数vTaskResumeFromISR()恢复一次,就可以继续运行。函数原型如下所示:

    在这里插入图片描述

2. vTaskSuspend源码分析

在这里插入图片描述

  1. 需将宏INCLUDE_vTaskSuspend 配置为 1

    // 使能挂起任务 
    #define INCLUDE_vTaskSuspend                            1                       
    
  2. 根据任务句柄获取任务控制块,如果任务句柄为NULL,表示挂起任务自身

    pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
    
  3. 将要挂起的任务从状态列表中移除

    //3.将要挂起的任务从状态列表中移除
    if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
    {
    	taskRESET_READY_PRIORITY( pxTCB->uxPriority );
    }
    else
    {
    	mtCOVERAGE_TEST_MARKER();
    }
    
    //3.将要挂起的任务从事件列表中移除
    if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
    {
    	( void ) uxListRemove( &( pxTCB->xEventListItem ) );
    }
    else
    {
    	mtCOVERAGE_TEST_MARKER();
    }
    
  4. 将待挂起任务的任务状态列表插入挂起任务列表末尾

    vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
    
    #if ( configUSE_TASK_NOTIFICATIONS == 1 )
    {
         BaseType_t x;
    
         for( x = 0; x < configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ )
         {
    			//如果待挂起任务在等待,停止等待,直接赋值为0
                if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION )
                 {  
                      pxTCB->ucNotifyState[ x ] = taskNOT_WAITING_NOTIFICATION;
                 }
         }
    }
    #endif 
    
  5. 判断任务调度器是否在运行

    //如果在运行,则更新下一次阻塞时间,防止被挂起任务为下一次阻塞超时任务
    if(xSchedulerRunning != pdFALSE)
    {
         taskENTER_CRITICAL();
         {
              prvResetNextTaskUnblockTime();
         }
         taskEXIT_CRITICAL();
    }
    else
    {
         mtCOVERAGE_TEST_MARKER();
    }
    
  6. 如果挂起的是当前任务,且调度器正在运行,需要进行一次任务切换,否则判断挂起任务数

    if( pxTCB == pxCurrentTCB )
    {
    	//且调度器正在运行,需要进行一次任务切换
    	if( xSchedulerRunning != pdFALSE )
    	{
    		configASSERT( uxSchedulerSuspended == 0 );
    		portYIELD_WITHIN_API();
    	}
    	//若没有运行,判断挂起任务数是否等于任务总数
    	//若相等,当前控制块赋值为NULL
    	//若不相等,寻找下一个最高优先级任务
    	else
    	{
    		if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) 
    		{
    			pxCurrentTCB = NULL;
    		}
    		else
    		{
    			vTaskSwitchContext();
    		}
    	}
    }
    else
    {
    	mtCOVERAGE_TEST_MARKER();
    }
    

具体实现:

#if ( INCLUDE_vTaskSuspend == 1 )

    void vTaskSuspend( TaskHandle_t xTaskToSuspend )
    {
        TCB_t * pxTCB;

        taskENTER_CRITICAL();
        {
            /* If null is passed in here then it is the running task that is
             * being suspended. */
			//2.根据任务句柄获取任务控制块,如果任务句柄为NULL,表示挂起任务自身
            pxTCB = prvGetTCBFromHandle( xTaskToSuspend );

            traceTASK_SUSPEND( pxTCB );

            /* Remove task from the ready/delayed list and place in the
             * suspended list. */
			//3.将要挂起的任务从状态列表中移除
            if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
            {
                taskRESET_READY_PRIORITY( pxTCB->uxPriority );
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }

            /* Is the task waiting on an event also? */
			//3.将要挂起的任务从事件列表中移除
            if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
            {
                ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
			
			//4.将待挂起任务的任务状态列表插入挂起任务列表末尾
            vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );

            #if ( configUSE_TASK_NOTIFICATIONS == 1 )
                {
                    BaseType_t x;

                    for( x = 0; x < configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ )
                    {
						//如果待挂起任务在等待,停止等待,直接赋值为0
                        if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION )
                        {
                            /* The task was blocked to wait for a notification, but is
                             * now suspended, so no notification was received. */
                            pxTCB->ucNotifyState[ x ] = taskNOT_WAITING_NOTIFICATION;
                        }
                    }
                }
            #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
        }
        taskEXIT_CRITICAL();
		
		//5.判断任务调度器是否在运行
		//如果在运行,则更新下一次阻塞时间,防止被挂起任务为下一次阻塞超时任务
        if( xSchedulerRunning != pdFALSE )
        {
            /* Reset the next expected unblock time in case it referred to the
             * task that is now in the Suspended state. */
            taskENTER_CRITICAL();
            {
                prvResetNextTaskUnblockTime();
            }
            taskEXIT_CRITICAL();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
		
		//6.如果挂起的是当前任务,
        if( pxTCB == pxCurrentTCB )
        {
			//且调度器正在运行,需要进行一次任务切换
            if( xSchedulerRunning != pdFALSE )
            {
                /* The current task has just been suspended. */
                configASSERT( uxSchedulerSuspended == 0 );
                portYIELD_WITHIN_API();
            }
			//若没有运行,判断挂起任务数是否等于任务总数
			//若相等,当前控制块赋值为NULL
			//若不相等,寻找下一个最高优先级任务
            else
            {
                /* The scheduler is not running, but the task that was pointed
                 * to by pxCurrentTCB has just been suspended and pxCurrentTCB
                 * must be adjusted to point to a different task. */
                if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) /*lint !e931 Right has no side effect, just volatile. */
                {
                    /* No other tasks are ready, so set pxCurrentTCB back to
                     * NULL so when the next task is created pxCurrentTCB will
                     * be set to point to it no matter what its relative priority
                     * is. */
                    pxCurrentTCB = NULL;
                }
                else
                {
                    vTaskSwitchContext();
                }
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }

#endif

3. vTaskResume源码分析

在这里插入图片描述

  1. 需将宏INCLUDE_vTaskSuspend配置为1

    #if ( INCLUDE_vTaskSuspend == 1 )
    
  2. 恢复任务不能是正在运行的任务

    if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) )
    
  3. 判断任务是否被挂起

    //若被挂起,就会将该任务从挂起列表中移除,将该任务添加到就绪列表中
    if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
    
  4. 判断恢复任务优先级是否大于当前正在运行的任务优先级

    //若是,要进行任务切换
    if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
    {
         taskYIELD_IF_USING_PREEMPTION();
    }
    

具体实现:

//1.需将宏INCLUDE_vTaskSuspend配置为1
#if ( INCLUDE_vTaskSuspend == 1 )

    void vTaskResume( TaskHandle_t xTaskToResume )
    {
        TCB_t * const pxTCB = xTaskToResume;

        /* It does not make sense to resume the calling task. */
        configASSERT( xTaskToResume );

        /* The parameter cannot be NULL as it is impossible to resume the
         * currently executing task. */
		//2.恢复任务不能是正在运行的任务
        if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) )
        {
            taskENTER_CRITICAL();
            {
				//3.判断任务是否被挂起
				//若被挂起,就会将该任务从挂起列表中移除,将该任务添加到就绪列表中
                if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
                {
                    traceTASK_RESUME( pxTCB );

                    /* The ready list can be accessed even if the scheduler is
                     * suspended because this is inside a critical section. */
                    ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
                    prvAddTaskToReadyList( pxTCB );

                    /* A higher priority task may have just been resumed. */
					//4.判断恢复任务优先级是否大于当前正在运行的任务优先级
					//若是,要进行任务切换
                    if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
                    {
                        /* This yield may not cause the task just resumed to run,
                         * but will leave the lists in the correct state for the
                         * next yield. */
                        taskYIELD_IF_USING_PREEMPTION();
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            taskEXIT_CRITICAL();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }

#endif

4. xTaskResumeFromISR源码分析

在这里插入图片描述

  1. 用于检测调用freertos的API函数的中断优先级是否在管理范围内,以及是否全部设置为抢占式优先级位

    portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
    
  2. 关闭freertos可管理中断,防止被其他的中断打断,并返回关闭前basepri寄存器的值

    uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    
  3. 判断是否有挂起任务

    if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
    {
    	traceTASK_RESUME_FROM_ISR( pxTCB );
    
    	/* Check the ready lists can be accessed. */
    	//检测调度器是否被挂起
    	//判断恢复的这个任务优先级是否大于正在执行的任务是的话将xYieldRequired标记
    	//为pdTRUE,表示需要进行一次任务切换
    	//将被恢复的任务从挂起列表中移除
    	//插入到就绪列表
    	if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
    	{
    		if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
    		{
    			xYieldRequired = pdTRUE;
    			xYieldPending = pdTRUE;
    		}
    		else
    		{
    			mtCOVERAGE_TEST_MARKER();
    		}
    
    		( void ) uxListRemove( &( pxTCB->xStateListItem ) );
    		prvAddTaskToReadyList( pxTCB );
    	}
    	//如果调度器被挂起了,就将恢复的任务插入等待就绪列表,直到调度器被恢复再进行任务的处理
    	else
    	{
    		vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
    	}
    }
    else
    {
    	mtCOVERAGE_TEST_MARKER();
    }
    
  4. 将前面保存的basepri的值,恢复回来

    portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
    
  5. 返回xYieldRequired的值 用于决定是否需要进行任务切换

    return xYieldRequired;
    

具体实现:

#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )

    BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume )
    {
        BaseType_t xYieldRequired = pdFALSE;
        TCB_t * const pxTCB = xTaskToResume;
        UBaseType_t uxSavedInterruptStatus;

        configASSERT( xTaskToResume );

        /* RTOS ports that support interrupt nesting have the concept of a
         * maximum  system call (or maximum API call) interrupt priority.
         * Interrupts that are  above the maximum system call priority are keep
         * permanently enabled, even when the RTOS kernel is in a critical section,
         * but cannot make any calls to FreeRTOS API functions.  If configASSERT()
         * is defined in FreeRTOSConfig.h then
         * portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
         * failure if a FreeRTOS API function is called from an interrupt that has
         * been assigned a priority above the configured maximum system call
         * priority.  Only FreeRTOS functions that end in FromISR can be called
         * from interrupts  that have been assigned a priority at or (logically)
         * below the maximum system call interrupt priority.  FreeRTOS maintains a
         * separate interrupt safe API to ensure interrupt entry is as fast and as
         * simple as possible.  More information (albeit Cortex-M specific) is
         * provided on the following link:
         * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
		//1.用于检测调用freertos的API函数的中断优先级是否在管理范围内,以及是否全部设置为抢占式优先级位
        portASSERT_IF_INTERRUPT_PRIORITY_INVALID();

		//2.关闭freertos可管理中断,防止被其他的中断打断,并返回关闭前basepri寄存器的值
        uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
        {
			//3.判断是否有挂起任务
            if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
            {
                traceTASK_RESUME_FROM_ISR( pxTCB );

                /* Check the ready lists can be accessed. */
				//检测调度器是否被挂起
				//判断恢复的这个任务优先级是否大于正在执行的任务是的话将xYieldRequired标记
				//为pdTRUE,表示需要进行一次任务切换
				//将被恢复的任务从挂起列表中移除
				//插入到就绪列表
                if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
                {
                    /* Ready lists can be accessed so move the task from the
                     * suspended list to the ready list directly. */
                    if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
                    {
                        xYieldRequired = pdTRUE;

                        /* Mark that a yield is pending in case the user is not
                         * using the return value to initiate a context switch
                         * from the ISR using portYIELD_FROM_ISR. */
                        xYieldPending = pdTRUE;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

                    ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
                    prvAddTaskToReadyList( pxTCB );
                }
				//如果调度器被挂起了,就将恢复的任务插入等待就绪列表,直到调度器被恢复再进行任务的处理
                else
                {
                    /* The delayed or ready lists cannot be accessed so the task
                     * is held in the pending ready list until the scheduler is
                     * unsuspended. */
                    vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
		//4.将前面保存的basepri的值,恢复回来
        portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
		
		//5.返回xYieldRequired的值 用于决定是否需要进行任务切换
        return xYieldRequired;
    }

#endif

5. 实验验证

实验目的:
在这里插入图片描述

任务函数:

  • 开始任务:

    /*开始任务*/
    void start_task(void* pvParamter)
    {
    	taskENTER_CRITICAL();   // 进入临界区 
    	
    	xTaskCreate((TaskFunction_t        )   task1,                 //指向任务函数的指针
    				(char *                )   "task1",               //任务名称
    				(configSTACK_DEPTH_TYPE)   TASK1_TASK_STACK_SIZE, //任务堆栈大小,字节为单位
    				(void *                )   NULL,                  //传递给任务函数的参数
    				(UBaseType_t           )   TASK1_TASK_PRIO,       //任务优先级
    				(TaskHandle_t *        )   &task1_task_handler    //任务句柄:任务控制块
    	);
    				
    	xTaskCreate((TaskFunction_t        )   task2,                 //指向任务函数的指针
    				(char *                )   "task2",               //任务名称
    				(configSTACK_DEPTH_TYPE)   TASK2_TASK_STACK_SIZE, //任务堆栈大小,字节为单位
    				(void *                )   NULL,                  //传递给任务函数的参数
    				(UBaseType_t           )   TASK2_TASK_PRIO,       //任务优先级
    				(TaskHandle_t *        )   &task2_task_handler    //任务句柄:任务控制块
    	);	
    
    	xTaskCreate((TaskFunction_t        )   task3,                  //指向任务函数的指针
    				(char *                )   "task3",                //任务名称
    				(configSTACK_DEPTH_TYPE)   TASK3_TASK_STACK_SIZE,  //任务堆栈大小,字节为单位
    				(void *                )   NULL,                   //传递给任务函数的参数
    				(UBaseType_t           )   TASK3_TASK_PRIO,        //任务优先级
    				(TaskHandle_t *        )   &task3_task_handler     //任务句柄:任务控制块
    	);
    
    	vTaskDelete(NULL);
    				
    	taskEXIT_CRITICAL();    // 退出临界区 
    }
    
  • 任务一:实现LED0每500ms翻转一次

    void task1(void* pvParamter)
    {
    	uint32_t task1_num = 0;
    	
    	while(1)
    	{
    		printf("task1正在运行!!!\r\n");
    		lcd_show_xnum(71, 80, ++task1_num, 3, 16, 0x80, GREEN);
    		LED0_TOGGLE();
    		vTaskDelay(500);
    	}
    }
    
  • 任务二:实现LED1每500ms翻转一次

    void task2(void* pvParamter)
    {
    	uint32_t task2_num = 0;
    	
    	while(1)
    	{
    		printf("task2正在运行!!!\r\n");
    		lcd_show_xnum(191, 80, ++task2_num, 3, 16, 0x80, GREEN);
    		LED1_TOGGLE();
    		vTaskDelay(500);
    	}
    }
    
  • 任务三:挂起和恢复任务一

    void task3(void* pvParamter)
    {
    	uint8_t key = 0;
    	while(1)
    	{
    		printf("task3正在运行!!!\r\n");
    		key = key_scan(0);
    		
    		switch(key)
    		{
    			case KEY0_PRES:
    				vTaskSuspend(task1_task_handler);	
    				break;
    			case KEY1_PRES:
    				vTaskResume(task1_task_handler);
    			    break;
    			default:
    				break;		
    		}		
    		vTaskDelay(10);
    	}
    }
    
  • 初始任务的创建与开启任务调度

    	xTaskCreate((TaskFunction_t        )   start_task,           //指向任务函数的指针
    				(char *                )   "start_task",         //任务名称
    				(configSTACK_DEPTH_TYPE)   START_TASK_STACK_SIZE,//任务堆栈大小,字节为单位
    				(void *                )   NULL,                 //传递给任务函数的参数
    				(UBaseType_t           )   START_TASK_PRIO,      //任务优先级
    				(TaskHandle_t *        )   &start_task_handler    //任务句柄:任务控制块
    	);
    				
        vTaskStartScheduler();  //开启任务调度
    

实验结果:
LCD显示屏与LED灯同时工作,LCD显示运行的次数,当按下按键,运行次数暂停,LED灯不再闪烁。当按下KEY1恢复任务后,任务1继续运行,LED灯与LCD显示屏计数开始工作。

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

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

相关文章

【Docker】Namespace 空间隔离实战

一、实战目的 了解隔离能力并不是 Docker 提供的&#xff0c;而是操作系统内核提供基本能力。 二、基础知识 1、dd 命令详解 Linux dd 命令用于读取、转换并输出数据。 dd 可从标准输入或文件中读取数据&#xff0c;根据指定的格式来转换数据&#xff0c;再输出到文件、…

直流电表常见的应用有哪些

直流电表作为电力系统中不可或缺的计量工具&#xff0c;其应用广泛且多样化。以下是对直流电表常见应用的详细归纳&#xff1a; 一、新能源发电系统 1. 太阳能光伏发电 应用背景&#xff1a;太阳能光伏发电系统通过太阳能电池板将光能转化为直流电能。直流电表在这一系统中扮…

浪潮NF5280M4虚拟磁盘OFFLINE和磁盘状态为“Frn-Bad”与“UB”故障处理

客户托管设备的机房异常断电&#xff0c;导致6台浪潮NF5280M4的系统无法访问&#xff0c;系统所在的RAID组中的2块磁盘全部亮故障灯。 通过设备管理界面检查&#xff0c;发现逻辑磁盘处于Offline状态&#xff1a; 物理磁盘也处于Offline状态&#xff1a; 进入BIOS RAID配置…

介绍几种 iutils.dll丢失的解决办法,iutils.dll文件详细介绍

电脑中经常会出现 iutils.dll文件丢失的情况&#xff0c;所以如果电脑中缺失 iutils.dll文件会让大家很苦恼&#xff0c;那么 iutils.dll丢失有什么解决办法呢&#xff1f;今天就给大家介绍几种 iutils.dll丢失的解决办法。 1. iutils.dll 文件的来源 iutils.dll 是一个动态链…

npm 修改 淘宝源

aliyun ECS npm 源也不顺畅了&#xff0c;哎 &#x1f611; npm config get registrynpm config set registry https://registry.npmmirror.com喜欢或对你有帮助&#xff0c;点个赞吧&#xff0c;自己先点个嘿嘿。 有错误或者疑问还请评论指出。 我的个人网站 点击访问 hongw…

暑假时光的趣味新选择:《米小圈漫画历史》的魅力探秘

当暑假的炎炎夏日来临&#xff0c;许多家长都会面临一个共同的挑战&#xff1a;如何让孩子远离手机屏幕&#xff0c;找到既有趣又有教育意义的活动。作为一名父母&#xff0c;我被这个问题所困扰。看着孩子一整天沉浸在电子设备中&#xff0c;我深知这不仅会影响他们的视力&…

web程序员转大模型岗位,零基础入门到精通非常详细,收藏我这一篇就够了

从Web程序员转型到大模型岗位&#xff0c;需要掌握一系列新技能和知识。以下是一个详细的攻略&#xff1a; 了解大模型基础&#xff1a; 学习大模型的基本概念&#xff0c;如Transformer架构、自注意力机制等。 阅读相关论文&#xff0c;如“Attention is All You Need”等。 …

Debug-019-git reflog的两种使用场景

前情&#xff1a;最近在开发项目中对版本管理有了新的理解&#xff0c;感觉在这方面有了新的收获。同时学习了一个新的git指令&#xff1a;git reflog 实际了解之后&#xff0c;发现这个指令不是很常用&#xff0c;但是对于特定的场景的话它还是非常比较方便 这里我列举两种我…

使用 LangChain 开发 LLM 应用(3):记忆

注: 本文是基于吴恩达《LangChain for LLM Application Development》课程的学习笔记&#xff1b;完整的课程内容以及示例代码/Jupyter笔记见&#xff1a;LangChain-for-LLM-Application-Development&#xff1b; 课程大纲 目前 LLM 基本上都有最大 Token 的限制&#xff0c;即…

IEEE计算智能学会深圳分会线上讲座 22-01期: 金耀初教授的科研经验分享

IEEE计算智能学会深圳分会线上讲座 22-01期: 金耀初教授的科研经验分享_哔哩哔哩_bilibili 非限定性定语从句&#xff0c;使用逗号和which、动名词搭配使用&#xff0c; 尽量避免使用被动语态。 obviously- 使用clearly,apparently感觉上更好。 In this study/work 后面的交…

C++重载左移运算符

通过重载左移运算符&#xff0c;可以实现cout << p;直接输出类对象的各个属性。 其只能使用全局函数重载。 注意cout的定义如下&#xff1a; _EXPORT_STD extern "C" __PURE_APPDOMAIN_GLOBAL _CRTDATA2_IMPORT ostream cout; 也就是说我们一直用来输出的c…

VirtualFlow案例 | 油箱燃油晃动模拟,高效分析管路及油箱内油面变化

在探索流体行为模拟的领域&#xff0c;CFD技术为油箱燃油晃动模拟带来了革命性的转变。通过高精度的数值模拟&#xff0c;它不仅揭示了燃油在不同工况下的复杂动态&#xff0c;还为油箱设计的优化提供了关键洞察。这一技术在航空航天、汽车制造、船舶与海洋工程等多个行业中展现…

Diffree - AI一键P图,告别P图困扰,只需要输入一段文字就能轻松玩转P图的神器 本地一键整合包下载

在这个AI技术飞速发展的时代&#xff0c;我们见证了许多神奇的创新&#xff0c;比如最近火遍朋友圈的“Diffree”。这可不是一款新推出的手机游戏&#xff0c;而是一项能让设计师和摄影师们欢呼雀跃的AI图像处理技术。 它能够根据你的文字描述&#xff0c;在图片中“无痕迹”地…

1_初识pytorch

之前完全没有了解过深度学习和pytorch&#xff0c;但现在因为某些原因不得不学了。不得不感叹&#xff0c;深度学习是真的火啊。纯小白&#xff0c;有错的欢迎指正~ 参考视频&#xff1a;PyTorch深度学习快速入门教程&#xff08;绝对通俗易懂&#xff01;&#xff09;【小土堆…

企业官网后台管理|网站后台管理系统PHP源码 开源

效果展示 提交反馈 获得更多开源资料 技术交流

在 Google Cloud 上大规模部署 dbt 项目

使用 Artifact Registry、Cloud Composer、GitHub Actions 和 dbt-airflow 容器化并运行 dbt 项目 欢迎来到雲闪世界。&#xff0c;大规模管理数据模型是使用dbt&#xff08;数据构建工具&#xff09;的数据团队面临的常见挑战。最初&#xff0c;团队通常从易于管理和部署的简单…

【日记】9 个发箍只有 2 个能压住头发……(513 字)

正文 今天下午实在有些受不了&#xff0c;从正大门外走了出去。抬头望着天空&#xff0c;望着那些悠然自在纯白无暇的云&#xff0c;竟然有些眼睛疼&#xff0c;刺激到想要流泪。 我在室内待得太久太久了。似乎很久没有在这种时间段出来过了。 下午快下班的时候&#xff0c;有个…

前端面试宝典【设计模式】【2】

欢迎来到《前端面试宝典》,这里是你通往互联网大厂的专属通道,专为渴望在前端领域大放异彩的你量身定制。通过本专栏的学习,无论是一线大厂还是初创企业的面试,都能自信满满地展现你的实力。 核心特色: 独家实战案例:每一期专栏都将深入剖析真实的前端面试案例,从基础知…

二进制部署k8s集群之cni网络插件flannel和calico工作原理

3、部署 CNI 网络组件 在 master01 节点上操作 上传flannel-v0.21.5.zip并解压 unzip flannel-v0.21.5.zipscp flannel*.tar 192.168.80.20:/opt/k8s/ scp flannel*.tar 192.168.80.30:/opt/k8s/ node两个节点操作 cd /opt/k8s/ docker load -i flannel.tar docker load -i …

Vue3开源Tree组件研发:节点勾选支持v-model

自研Tree组件有两个原因&#xff1a;1. 目前开源UI对Tree组件的用户API不太友好&#xff0c;2. 提升Vue3组件自研能力。 目前已实现的功能见上面思维导图。想象Tree组件的一个使用场景&#xff1a;后台管理员通过Tree组件来完成用户角色授权&#xff0c;同时支持对权限进行新增…