15_FreeRtos计数信号量优先级翻转互斥信号量

news2024/11/16 1:47:43

目录

计数型信号量

计数型信号量相关API函数

计数型信号量实验源码

优先级翻转简介

优先级翻转实验源码

互斥信号量

互斥信号量相关API函数

互斥信号量实验源码


计数型信号量

计数型信号量相当于队列长度大于1的队列,因此计数型信号量能够容纳多个资源,这在计数型信号量被创建的时候确定的

计数型信号量适用场合:

事件计数

当每次事件发生后,在事件处理函数中释放计数型信号量(计数值+1) ,其他任务会获取计数型信号量(计数值-1),这种场合一般在创建时将初始计数值设置为 0

资源管理

信号量表示有效的资源数目。任务必须先获取信号量(信号量计数值-1)才能获取资源控制权。当计数值减为零时表示没有的资源。当任务使用完资源后,必须释放信号量(信号量计数值+1)信号量创建时计数值应等于最大资源数目

计数型信号量相关API函数

使用计数型信号量的过程:创建计数型信号量 → 释放信号量 → 获取信号量

 计数型信号量的释放和获取与二值信号量相同!

此函数用于创建一个计数型信号量。

#definexSemaphoreCreateCounting( uxMaxCount , uxInitialCount )  \
xQueueCreateCountingSemaphore( ( uxMaxCount), ( uxlnitialCount ))

此函数用于获取信号量当前计数值大小 

#defineuxSemaphoreGetCount( xSemaphore) \

 uxQueueMessagesWaiting( (QueueHandle_t) (xSemaphore ))

计数型信号量实验源码

将设计三个任务: start_task、task1、task2

start_task :用来创建task1和task2任务

Task1:用于按键扫描,当检测到按键KEY0被按下时,释放计数型信号量

task2:每过一秒获取一次计数型信号量,当成功获取后打印信号量计数值

/**
  ******************************************************************************
  * @file           : user_mian.h
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdbool.h>
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "user_key.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/*二值信号量句柄*/
QueueHandle_t count_semphore_handle;
/* Variables 变量--------------------------------------------------------------*/ 
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/

//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);


//任务优先级
#define TASK1_PRIO			3
//任务堆栈大小	
#define TASK1_STK_SIZE 		100  
//任务句柄
TaskHandle_t Task1_Handler;
//任务函数
void task1(void *pvParameters);


//任务优先级
#define TASK2_PRIO			3
//任务堆栈大小	
#define TASK2_STK_SIZE 		100  
//任务句柄
TaskHandle_t Task2_Handler;
//任务函数
void task2(void *pvParameters);



 int main(void)
 {	

	/*配置系统中断分组为4位抢占*/
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	 /*延时函数初始化*/
	 delay_init();
	/*RCC配置*/
	 Rcc_config();
	/*GPIO初始化*/ 
	 Gpio_Init();
	/*USART1初始化*/
	 Uart1_Init(9600);
	 /*创建计数型信号量最大值100,初始化值为0*/
	 count_semphore_handle = xSemaphoreCreateCounting(100,0); 
	 
	 if(count_semphore_handle != NULL)
	 {
		printf("计数型信号量创建成功初始值为0\r\n\r\n");
	 }
	 
	 /*创建开始任务*/
    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();          //开启任务调度
		

}
 

/*!
	\brief		开始任务函数
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
    //创建任务1
    xTaskCreate((TaskFunction_t )task1,     	
                (const char*    )"task1",   	
                (uint16_t       )TASK1_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )TASK1_PRIO,	
                (TaskHandle_t*  )&Task1_Handler);   
    //创建任务2
    xTaskCreate((TaskFunction_t )task2,     
                (const char*    )"task2",   
                (uint16_t       )TASK2_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2_Handler); 

				
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}


/*!
	\brief		task1释放计数型信号量
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void task1(void *pvParameters)
{
	uint8_t key = 0;
    while(1)
    {	
		/*获取按键值*/
		key = Key_Scan(0);
		
		if(key == KEY0_PRES)
		{
			if(count_semphore_handle != NULL)
			{					 
				if(xSemaphoreGive(count_semphore_handle))
				{
					taskENTER_CRITICAL();           //进入临界区
					printf("计数型信号量释放成功当前值为%d\r\n\r\n",(int)uxSemaphoreGetCount(count_semphore_handle));
				    taskEXIT_CRITICAL();            //退出临界区
				}
			}		
		}
		
		vTaskDelay(10);
    }
} 


/*!
	\brief		task2获取计数型信号量
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void task2(void *pvParameters)
{
	BaseType_t err;
    while(1)
    {
		/*获取信号量死等,进入阻塞态*/
		err = xSemaphoreTake(count_semphore_handle,portMAX_DELAY);	
		if(err == pdTRUE)
		{
			taskENTER_CRITICAL();           //进入临界区	
			printf("信号量的计数值为:%d\r\n\r\n",(int)uxSemaphoreGetCount(count_semphore_handle));		
		    taskEXIT_CRITICAL();            //退出临界区
		}
			
		vTaskDelay(1000);
    }
}



 /************************************************************** END OF FILE ****/

 

优先级翻转简介

优先级翻转:高优先级的任务反而慢执行,低优先级的任务反而优先执行

优先级翻转在抢占式内核中是非常常见的,但是在实时操作系统中是不允许出现优先级翻转的,因为优先级翻转会破坏任务的预期顺序,可能会导致未知的严重后果。

在使用二值信号量的时候,经常会遇到优先级翻转的问题。

举例:

任务H 优先级最高 任务M优先级中等  任务L优先级最低

假设任务L正在运行获取了信号量,其他2任务在阻塞状态,此时任务H就绪抢占了任务L,任务H也是获取信号量,发现信号量没有了进入阻塞态,继续执行任务L(优先级翻转了),然后任务M就绪抢占了任务L,任务M执行完后,进入阻塞态,任务H一直在等信号量所以一直在阻塞态,任务L继续运行,直到释放了信号量后,任何H才会从阻塞态变成就绪态执行。

高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度,但其他中等优先级的任务却能抢到CPU资源。从现象上看,就像是中优先级的任务比高优先级任务具有更高的优先权(即优先级翻转)

优先级翻转实验源码

在使用二值信号量的时候会存在优先级翻转的问题,本实验通过模拟的方式实现优先级翻转,观察优先级翻转对抢占式内核的影响

将设计四个任务:start_task、high_task、middle_task, low_task

start_task:用来创建其它任务

high_task:高优先级任务,会获取二值信号量,获取成功以后打印提示信息,处理完后释放信号量

middle_task:中等优先级任务,简单的应用任务

low_task:低优先级任务,同高优先级一样的操作,不同的是低优先级任务占用信号量的时间久一点

/**
  ******************************************************************************
  * @file           : user_mian.h
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdbool.h>
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "user_key.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/*二值信号量句柄*/
QueueHandle_t semphore_handle;
/* Variables 变量--------------------------------------------------------------*/ 
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/

//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);


//任务优先级
#define HIGH_PRIO			4
//任务堆栈大小	
#define HIGH_STK_SIZE 		100  
//任务句柄
TaskHandle_t HIGH_Handler;
//任务函数
void high_task(void *pvParameters);


//任务优先级
#define MIDDLE_PRIO			3
//任务堆栈大小	
#define MIDDLE_STK_SIZE 		100  
//任务句柄
TaskHandle_t MIDDLE_Handler;
//任务函数
void middle_task(void *pvParameters);

//任务优先级
#define LOW_PRIO			2
//任务堆栈大小	
#define LOW_STK_SIZE 		100  
//任务句柄
TaskHandle_t LOW_Handler;
//任务函数
void low_task(void *pvParameters);


 int main(void)
 {	

	/*配置系统中断分组为4位抢占*/
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	 /*延时函数初始化*/
	 delay_init();
	/*RCC配置*/
	 Rcc_config();
	/*GPIO初始化*/ 
	 Gpio_Init();
	/*USART1初始化*/
	 Uart1_Init(9600);
	 /*创建二值信号量*/
	 semphore_handle = xSemaphoreCreateBinary(); 
	 
	 if(semphore_handle == NULL)
	 {
		printf("二值信号量创建不成功\r\n\r\n");
	 }else
	 {
		printf("二值信号量创建成功\r\n\r\n");
	 }
	 /*二值释放信号量*/
	 xSemaphoreGive(semphore_handle);
	 /*创建开始任务*/
    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();          //开启任务调度
		

}
 

/*!
	\brief		开始任务函数
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
    //创建高优先级任务
    xTaskCreate((TaskFunction_t )high_task,     	
                (const char*    )"high_task",   	
                (uint16_t       )HIGH_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )HIGH_PRIO,	
                (TaskHandle_t*  )&HIGH_Handler);   
    //创建中优先级任务
    xTaskCreate((TaskFunction_t )middle_task,     
                (const char*    )"middle_task",   
                (uint16_t       )MIDDLE_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )MIDDLE_PRIO,
                (TaskHandle_t*  )&MIDDLE_Handler); 
    //创建低优先级任务
    xTaskCreate((TaskFunction_t )low_task,     
                (const char*    )"low_task",   
                (uint16_t       )LOW_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LOW_PRIO,
                (TaskHandle_t*  )&LOW_Handler); 
				
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}


/*!
	\brief		高优先级任务
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void high_task(void *pvParameters)
{

    while(1)
    {	
		taskENTER_CRITICAL();           //进入临界区
		printf("high_task获取信号量\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		/*获取二值信号量,并死等方式*/
		xSemaphoreTake(semphore_handle,portMAX_DELAY);
		taskENTER_CRITICAL();           //进入临界区
		printf("high_task正在运行\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		delay_xms(1000);
		/*释放二值信号量*/
		taskENTER_CRITICAL();           //进入临界区
		printf("high_task释放信号量\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		xSemaphoreGive(semphore_handle);
		vTaskDelay(10);
    }
} 


/*!
	\brief		中优先级任务
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void middle_task(void *pvParameters)
{

    while(1)
    {
		taskENTER_CRITICAL();           //进入临界区
		printf("middle_task正在运行\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区

		vTaskDelay(1000);
    }
}



/*!
	\brief		低优先级任务
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void low_task(void *pvParameters)
{

	while(1)
	{    
		taskENTER_CRITICAL();           //进入临界区
		printf("low_task获取信号量\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		/*获取二值信号量,并死等方式*/
		xSemaphoreTake(semphore_handle,portMAX_DELAY);
		taskENTER_CRITICAL();           //进入临界区		
		printf("low_task正在运行\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		delay_xms(3000);
		/*释放二值信号量*/
		taskENTER_CRITICAL();           //进入临界区
		printf("low_task释放信号量\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		xSemaphoreGive(semphore_handle);
		vTaskDelay(1000);		
	
	}



}
 /************************************************************** END OF FILE ****/

互斥信号量

互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中!

优先级继承:当一个互斥信号量正在被一个低优先级的任务持有时,如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级。

 此时任务H的阻塞时间仅仅是任务L的执行时间,将优先级翻转的危害降到了最低

优先级继承并不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响

注意:互斥信号量不能用于中断服务函数中,原因如下:

  1. 互斥信号量有任务优先级继承的机制,但是中断不是任务,没有任务优先级,所以互斥信号量只能用与任务中,不能用于中断服务函数。
  2. 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。

互斥信号量相关API函数

使用互斥信号量:首先将宏configUSE_MUTEXES置一

使用流程:创建互斥信号量→ (task)获取信号量→ (give)释放信号量

创建互斥信号量函数

 互斥信号量的释放和获取函数与二值信号量相同!只不过互斥信号量不支持中断中调用

注意:创建互斥信号量时,会主动释放一次信号量

#define xSemaphoreCreateMutex()  xQueueCreateMutex( queueQUEUE_TYPE_MUTEX)

此函数用于创建互斥信号量

互斥信号量实验源码

在优先级翻转实验的基础,加入互斥信号量,解决优先级翻转问题

/**
  ******************************************************************************
  * @file           : user_mian.h
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdbool.h>
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "user_key.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/*二值信号量句柄*/
QueueHandle_t mutex_semphore_handle;
/* Variables 变量--------------------------------------------------------------*/ 
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/

//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);


//任务优先级
#define HIGH_PRIO			4
//任务堆栈大小	
#define HIGH_STK_SIZE 		100  
//任务句柄
TaskHandle_t HIGH_Handler;
//任务函数
void high_task(void *pvParameters);


//任务优先级
#define MIDDLE_PRIO			3
//任务堆栈大小	
#define MIDDLE_STK_SIZE 		100  
//任务句柄
TaskHandle_t MIDDLE_Handler;
//任务函数
void middle_task(void *pvParameters);

//任务优先级
#define LOW_PRIO			2
//任务堆栈大小	
#define LOW_STK_SIZE 		100  
//任务句柄
TaskHandle_t LOW_Handler;
//任务函数
void low_task(void *pvParameters);


 int main(void)
 {	

	/*配置系统中断分组为4位抢占*/
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	 /*延时函数初始化*/
	 delay_init();
	/*RCC配置*/
	 Rcc_config();
	/*GPIO初始化*/ 
	 Gpio_Init();
	/*USART1初始化*/
	 Uart1_Init(9600);
	 /*创建互斥信号量,默认释放一次*/
	 mutex_semphore_handle = xSemaphoreCreateMutex(); 
	 
	 if(mutex_semphore_handle == NULL)
	 {
		printf("互斥信号量创建不成功\r\n\r\n");
	 }else
	 {
		printf("互斥信号量创建成功\r\n\r\n");
	 }
	 /*创建开始任务*/
    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();          //开启任务调度
		

}
 

/*!
	\brief		开始任务函数
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
    //创建高优先级任务
    xTaskCreate((TaskFunction_t )high_task,     	
                (const char*    )"high_task",   	
                (uint16_t       )HIGH_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )HIGH_PRIO,	
                (TaskHandle_t*  )&HIGH_Handler);   
    //创建中优先级任务
    xTaskCreate((TaskFunction_t )middle_task,     
                (const char*    )"middle_task",   
                (uint16_t       )MIDDLE_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )MIDDLE_PRIO,
                (TaskHandle_t*  )&MIDDLE_Handler); 
    //创建低优先级任务
    xTaskCreate((TaskFunction_t )low_task,     
                (const char*    )"low_task",   
                (uint16_t       )LOW_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LOW_PRIO,
                (TaskHandle_t*  )&LOW_Handler); 
				
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}


/*!
	\brief		高优先级任务
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void high_task(void *pvParameters)
{

    while(1)
    {	
		taskENTER_CRITICAL();           //进入临界区
		printf("high_task获取信号量\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		/*获取二值信号量,并死等方式*/
		xSemaphoreTake(mutex_semphore_handle,portMAX_DELAY);
		taskENTER_CRITICAL();           //进入临界区
		printf("high_task正在运行\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		delay_xms(1000);
		/*释放二值信号量*/
		taskENTER_CRITICAL();           //进入临界区
		printf("high_task释放信号量\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		xSemaphoreGive(mutex_semphore_handle);
		vTaskDelay(10);
    }
} 


/*!
	\brief		中优先级任务
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void middle_task(void *pvParameters)
{

    while(1)
    {
		taskENTER_CRITICAL();           //进入临界区
		printf("middle_task正在运行\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区

		vTaskDelay(1000);
    }
}



/*!
	\brief		低优先级任务
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void low_task(void *pvParameters)
{

	while(1)
	{    
		taskENTER_CRITICAL();           //进入临界区
		printf("low_task获取信号量\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		/*获取二值信号量,并死等方式*/
		xSemaphoreTake(mutex_semphore_handle,portMAX_DELAY);
		taskENTER_CRITICAL();           //进入临界区		
		printf("low_task正在运行\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		delay_xms(3000);
		/*释放二值信号量*/
		taskENTER_CRITICAL();           //进入临界区
		printf("low_task释放信号量\r\n\r\n");
		taskEXIT_CRITICAL();            //退出临界区
		xSemaphoreGive(mutex_semphore_handle);
		vTaskDelay(1000);		
	
	}



}
 /************************************************************** END OF FILE ****/

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

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

相关文章

家庭理财,轻松记账修改收支记录这样操作

我们在记账的时候难免会出现记错或者想修改的地方&#xff0c;又或者是想将之前太久没有用的记账记录删除掉&#xff0c;今天&#xff0c;小编就教大家如何修改收支记录&#xff0c;一起接着往下看吧&#xff01; 第一步&#xff0c;运行【晨曦记账本】在软件主界面中&#xff…

分享111个HTML娱乐休闲模板,总有一款适合您

分享111个HTML娱乐休闲模板&#xff0c;总有一款适合您 111个HTML娱乐休闲模板下载链接&#xff1a;https://pan.baidu.com/s/1mqmJLctj9oQbJt6Oo8IuBA?pwdep3t 提取码&#xff1a;ep3t Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 响应式美容养生服务行业…

Yolo系列之YOLOv1 YOLOv2

一、YOLOv1 1. YOLOv1概述 YOLOv1是单阶段目标检测方法,不需要像Faster RCNN这种两阶段目标检测方法一样,需要生成先验框。Yolo算法采用一个单独的CNN模型实现end-to-end的目标检测。虽然Faster-RCNN在当时是mAP最高的算法(2015-2016年), 然而速度却很慢,相对而言,Yol…

Java智慧校园平台源码:SaaS模式智慧校园运营云平台源码

校班务管理&#xff1a;评价管理&#xff1a; 1.web端/教师端小程序编辑点评 多元化评价&#xff0c;捕捉学生闪光点全方位评价&#xff0c;自定义评价类型、 评价信息实时推送至家长、AI智能点评 班级报表一键导出&#xff0c;智能评测学生在校表现&#xff0c;老师、家长实…

算法的时间复杂度

算法在编写成可执行程序后&#xff0c;运行时需要消耗时间资源和空间&#xff08;内存&#xff09;资源&#xff0c;因此衡量一个算法的好坏&#xff0c;一般是从时间和空间两个维度来衡量的。 时间复杂度主要衡量一个算法运行的快慢&#xff0c;而空间复杂度主要衡量一个算法运…

Qt Desginer布局方法

首先将我们需要的控件拖拽到一个合适的位置&#xff0c;该例子中用到了两个label&#xff0c;两个lineEdit和两个pushButton。 然后我们需要利用弹簧来控制控件到控件之间的距离以及控件到窗体边界的距离&#xff0c;因为这里只有一组控件&#xff08;两个label&#xff0c;两个…

学板绘课程学费一般多少钱

学板绘课程学费一般多少钱&#xff1f;培训机构的费用和师资、模式有关&#xff0c;价格贵不贵要结合相同类型的机构多多对比。因为好些平台做了很多的宣传广告&#xff0c;运营成本很高&#xff0c; 终羊毛出在羊身上&#xff0c;这样的机构知名度很高&#xff0c;但是性价比不…

untiy 录制网络摄像头视频并保存到本地文件

网络摄像头使用的是海康威视的&#xff0c;关于如何使用Ump插件播放海康威视rtsp视频流&#xff0c;请参考我的这篇文章 内部有ump插件的下载链接 untiy接入 海康威视网络摄像头 录屏使用的插件是 AVPro movieCapture 4.6.3版&#xff0c; 插件和完整工程的下载链接放在本文的…

eclipse创建第一个java web项目并运行

为了能编写java web项目&#xff0c;建议安装支持javaee开发的eclipse版本。1.下载eclipse地址&#xff1a;https://www.eclipse.org/downloads/packages/release/2021-03/r2.解压后启动eclipse3.新建java web工程设置项目名称&#xff0c;指定tomcat的版本及路径4. 添加一个js…

Python快速入门系列之一:Python对象

Python对象1. 列表&#xff08;list&#xff09;2. 元组&#xff08;tuple&#xff09;3. 字典&#xff08;dict&#xff09;4. 集合&#xff08;set&#xff09;5. 字符串&#xff08;string&#xff09;6. BIF &#xff08;Built-in Function&#xff09;7. 列表、集合以及字…

小笔记:gitlab配置文件 /etc/gitlab/gitlab.rb 配置项

小笔记&#xff1a;gitlab配置文件 /etc/gitlab/gitlab.rb 配置项CSDN账号 jcLee95 &#xff1a;https://blog.csdn.net/qq_28550263?spm1001.2101.3001.5343 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/12…

0.3调试opencv源码的两种方式

调试opencv源码的两种方式 上两篇我们分别讲了如何配置opencv环境&#xff0c;以及如何编译opencv源码方便我们阅读。但我们还是无法调试我们的代码&#xff0c;无法以我们的程序作为入口来一步一步单点调试看opencv是如何执行的。 【opencv源码解析0.1】VS如何优雅的配置ope…

Python学习-----模块1.0(模块的简介、定义与使用)

目录 前言&#xff1a; 1.什么是模块 2.模块的分类 &#xff08;1&#xff09;内置模块 &#xff08;2&#xff09;第三方模块 &#xff08;3&#xff09;自定义模块 3.模块的使用 4.自定义模块 5.模块和执行文件的判断 前言&#xff1a; 今天就开始讲Python中的模块篇…

第07章_单行函数

第07章_单行函数 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 1. 函数的理解 1.1 什么是函数 函数在计算机语言的使用中贯穿始终&#xff0c;函数的作用是什么呢&#xff1f;它可以把我们经…

netty心跳

为什么要引入心跳机制&#xff1a;因为网络连接是不可靠的&#xff0c;像在TCP长连接或者webSocket长连接时都会使用心跳机制&#xff0c;即发送特殊的数据包告诉自己的业务没办完&#xff0c;不要关闭连接。案例要求&#xff1a;当服务器超过3秒没有读时&#xff0c;就提示读空…

二维数组中的查找(两种解法,各有千秋)

凡事都有可能&#xff0c;永远别说永远。——《放牛班的春天》今天一题为再一个行列都有序的二维数组中寻找一个目标值&#xff0c;我们第一时间想到的可能是很暴力的解法&#xff0c;例如从头到尾进行遍历&#xff0c;这样能做出来&#xff0c;但是借用武忠祥老师的一句话&…

15-基础加强-1-类加载器反射

文章目录1.类加载器1.1类加载器【理解】1.2类加载的过程【理解】1.3类加载的分类【理解】1.4双亲委派模型【理解】1.5ClassLoader 中的两个方法【应用】2.反射2.1反射的概述【理解】2.2获取Class类对象的三种方式【应用】 第1步&#xff1a;获取类的Class对象2.3反射获取构造方…

【FiddlerScript】利用Fiddler中的FiddlerScript解除4399小游戏的防沉迷

本文仅供技术探讨&#xff0c;切勿用于非法用途案例网站:小游戏,4399小游戏,小游戏大全,双人小游戏大全 - www.4399.com准备的工具:配置好的Fiddler一个Fiddler官方英文版配置教程:https://www.bilibili.com/video/BV1rP4y1t7ZLFiddler中文版配重教程:https://www.bilibili.com…

懒加载以及预加载相关概念

⼆、懒加载 1. 懒加载的概念 懒加载也叫做延迟加载、按需加载&#xff0c;指的是在⻓⽹⻚中延迟加载图⽚数据&#xff0c;是⼀种较好的⽹⻚性能优化 的⽅式。 在⽐较⻓的⽹⻚或应⽤中&#xff0c;如果图⽚很多&#xff0c;所有的图⽚都被加载出来&#xff0c;⽽⽤户只能看到…

创建vue项目

前提安装node.js 安装vue脚手架 命令: npm install -g vue/cli 安装完成后查看下版本 vue --version 开始创建vue项目,可以用cmd终端也可以用pow(Windows PowerShell) 搜索输入pow以管理员运行 找一个项目存放位置 pow进入该目录 创建项目命令 如果创建项目时候报错 输入…