15_FreeRtos计数信号量优先级翻转互斥信号量
目录
计数型信号量
计数型信号量相关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(); //进入临界区//创建任务1xTaskCreate((TaskFunction_t )task1, (const char* )"task1", (uint16_t )TASK1_STK_SIZE, (void* )NULL, (UBaseType_t )TASK1_PRIO, (TaskHandle_t* )&Task1_Handler); //创建任务2xTaskCreate((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的执行时间,将优先级翻转的危害降到了最低
优先级继承并不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响
注意:互斥信号量不能用于中断服务函数中,原因如下:
- 互斥信号量有任务优先级继承的机制,但是中断不是任务,没有任务优先级,所以互斥信号量只能用与任务中,不能用于中断服务函数。
- 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。
互斥信号量相关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 ****/

相关文章:
15_FreeRtos计数信号量优先级翻转互斥信号量
目录 计数型信号量 计数型信号量相关API函数 计数型信号量实验源码 优先级翻转简介 优先级翻转实验源码 互斥信号量 互斥信号量相关API函数 互斥信号量实验源码 计数型信号量 计数型信号量相当于队列长度大于1的队列,因此计数型信号量能够容纳多个资源,这在…...
二叉树(一)
二叉树(一)1.树的概念2.树的相关概念3.树的表示4.树在实际中的运用5.二叉树概念及结构6.特殊的二叉树7.二叉树的性质🌟🌟hello,各位读者大大们你们好呀🌟🌟 🚀🚀系列专栏…...
【SCL】1200案例:天塔之光数码管显示液体混合水塔水位
使用scl编写天塔之光&数码管显示&液体混合&水塔水位 文章目录 目录 文章目录 前言 一、案例1:天塔之光 1.控制要求 2.编写程序 3.效果 二、案例2:液体混合 1.控制要求 2.编写程序 三、案例3:数码管显示 1.控制要求 2.编写程序 3…...
5.1配置IBGP和EBGP
5.2.1实验1:配置IBGP和EBGP 实验目的 熟悉IBGP和EBGP的应用场景掌握IBGP和EBGP的配置方法 实验拓扑 实验拓扑如图5-1所示: 图5-1:配置IBGP和EBGP 实验步骤 IP地址的配置 R1的配置 <Huawei>system-view Enter system view, return …...
c++中超级详细的一些知识,新手快来
目录 2.文章内容简介 3.理解虚函数表 3.1.多态与虚表 3.2.使用指针访问虚表 4.对象模型概述 4.1.简单对象模型 4.2.表格驱动模型 4.3.非继承下的C对象模型 5.继承下的C对象模型 5.1.单继承 5.2.多继承 5.2.1一般的多重继承(非菱形继承) 5.2…...
[答疑]经营困难时期谈建模和伪创新-长点心和长点良心
leonll 2022-11-26 9:53 我们今年真是太难了……(此处删除若干字)……去年底就想着邀请您来给我们讲课,现在也没有实行。我想再和我们老大提,您觉得怎么说个关键理由,这样的形势合适引进UML开发流程? UML…...
计算机基础知识
计算机网络的拓扑结构 一、OSI 7层网络模型是指什么? 7层分别是什么?每层的作用是什么? OSI7层模型是 国际标准化组织(ISO)制定的一个用于计算机或通信系统间互联的标准体系。 每层功能:(自底向上) 物理层:建立、…...
Java爬虫—WebMagic
一,WebMagic介绍WebMagic企业开发,比HttpClient和JSoup更方便一),WebMagic架构介绍WebMagic有DownLoad,PageProcessor,Schedule,Pipeline四大组件,并有Spider将他们组织起来…...
[软件工程导论(第六版)]第2章 可行性研究(复习笔记)
文章目录2.1 可行性研究的任务2.2 可行性研究过程2.3 系统流程图2.4 数据流图概念2.5 数据字典2.6 成本/效益分析2.1 可行性研究的任务 可行性研究的目的 用最小的代价在尽可能短的时间内确定问题是否能够解决。 可行性研究的3个方面 (1)技术可行性&…...
Mac下安装Tomcat以及IDEA中的配置
安装brew 打开终端输入以下命令: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 搜索tomcat版本,输入以下命令: brew search tomcat 安装自己想要的版本,例…...
【Linux详解】——文件基础(I/O、文件描述符、重定向、缓冲区)
📖 前言:本期介绍文件基础I/O。 目录🕒 1. 文件回顾🕘 1.1 基本概念🕘 1.2 C语言文件操作🕤 1.2.1 概述🕤 1.2.2 实操🕤 1.2.3 OS接口open的使用(比特位标记)…...
HomMat2d
1.affine_trans_region(区域的任意变换) 2.hom_mat2d_identity(创建二位变换矩阵) 3.hom_mat2d_translate(平移) 4.hom_mat2d_scale(缩放) 5.hom_mat2d_rotate(旋转 &…...
Python3 JSON 数据解析
Python3 JSON 数据解析 JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。 Python3 中可以使用 json 模块来对 JSON 数据进行编解码,它包含了两个函数: json.dumps(): 对数据进行编码。json.loads(): 对数据进行解码。 在 json 的编解码…...
Homebrew 安装遇到的问题
Homebrew 安装遇到的问题 例如:第一章 Python 机器学习入门之pandas的使用 文章目录Homebrew 安装遇到的问题前言一、安装二、遇到的问题1.提示 zsh: command not found: brew三、解决问题前言 使用 Homebrew 能够 安装 Apple(或您的 Linux 系统&#…...
Metasploit框架基础(二)
文章目录前言一、Meatsplooit的架构二、目录结构datadocumentationlibmodulesplugins三、Measploit模块四、Metasploit的使用前言 Metasploit是用ruby语言开发的,所以你打开软件目录,会发现很多.rb结尾的文件。ruby是一门OOP的语言。 一、Meatsplooit的…...
c++容器
1、vector容器 1.1性质 a)该容器的数据结构和数组相似,被称为单端数组。 b)在存储数据时不是在原有空间上往后拓展,而是找到一个新的空间,将原数据深拷贝到新空间,释放原空间。该过程被称为动态拓展。 vec…...
Vue.js如何实现对一千张图片进行分页加载?
目录 vue处理一千张图片进行分页加载 分页加载、懒加载---概念介绍: 思路: 开发过程中,如果后端一次性返回你1000多条图片或数据,那我们前端应该怎么用什么思路去更好的渲染呢? 第一种:我们可以使用分页…...
计算机网络复习(六)
考点:MIME及其编码(base64,quoted-printable)网络协议http是基于什么协议,应用层到网络层基于什么协议6-27.试将数据 11001100 10000001 00111000 进行 base64 编码,并得到最后传输的 ASCII 数据。答:先将 24 比特的二…...
Redis进阶:布隆过滤器(Bloom Filter)及误判率数学推导
1 缘起 有一次偶然间听到有同事在说某个项目中使用了布隆过滤器, 哎呦,我去,我竟然不知道啥是布隆过滤器, 这我哪能忍?其实,也可以忍,但是,可能有的面试官不能忍!&#…...
Java创建对象的方式
Java创建对象的五种方式: (1)使用new关键字 (2)使用Object类的clone方法 (3)使用Class类的newInstance方法 (4)使用Constructor类中的newInstance方法 (5&am…...
小爱音箱 + XiaoMusic,NAS 本地音乐自由真的香
XiaoMusic 是一款专为小爱音箱打造的本地音乐管理工具,核心功能是绑定小米账号后,让小爱音箱直接读取 NAS 中存储的音乐文件,支持语音点播、随机播放、循环歌单等操作,适配所有能运行 Docker 的设备,无论是 NAS 还是普…...
全面解析MySQL与MSSQL数据库注入攻击的防范编码实践
在当今的Web应用开发中,数据库安全是构建健壮系统的基石。SQL注入攻击作为一种古老却依然活跃的安全威胁,其核心原理是攻击者通过在用户输入中插入恶意的SQL代码,欺骗后端数据库执行非预期的命令。无论是开源的MySQL还是商业的Microsoft SQL …...
Lychee-Rerank模型微调实战:使用领域数据提升垂直搜索效果
Lychee-Rerank模型微调实战:使用领域数据提升垂直搜索效果 你是不是遇到过这种情况?用一个通用的搜索系统去查专业资料,比如找某个疾病的治疗方案,或者某个法律条款的详细解释,结果搜出来的东西要么不相关,…...
自动化——1.python基础知识点梳理
Python基础字符串格式化常用方法列表添加元素删除元素切片字典json布尔表达式算术运算符比较运算符逻辑运算符in 和 not in循环for字符串随机数列表字典for else(else中的必执行)while三元表达式异常处理拓展星号的作用算术运算构造与解构函数参数限制函…...
避坑指南:Spring WebFlux中SSE连接意外中断的5种修复方案
Spring WebFlux中SSE连接稳定性深度优化指南 1. 理解SSE连接中断的核心痛点 在实时数据推送场景中,Server-Sent Events(SSE)因其简单性和与HTTP协议的天然兼容性而广受欢迎。但当我们将其与Spring WebFlux的响应式编程模型结合时,…...
告别Google Maps SDK,手把手教你用MapLibre Native 11.0.0为Android App集成免费开源地图
告别Google Maps SDK:用MapLibre Native 11.0.0为Android应用打造开源地图解决方案 当Google Maps SDK的商业授权费用成为项目预算的不可承受之重,或是功能限制让开发者束手束脚时,MapLibre Native以其开源免费的特性正成为越来越多Android开…...
上位机开发初体验|第一个项目从 0 到 1:项目创建与整体 UI 布局
作为上位机开发的新手,我的第一个项目从基础的项目搭建和 UI 布局开始入手,这一步也是整个项目的基础,做好窗体、容器、控件的基础样式配置,能为后续的功能开发打下整洁的框架。以下是我整理的详细操作步骤,亲测实用&a…...
FPGA嵌入式开发中8类主流I/O标准选型指南
1. 番外篇:I/O Type 扩展知识详解在嵌入式硬件开发,尤其是基于FPGA的可编程逻辑系统设计中,I/O电气标准(I/O Type)远非简单的“高电平/低电平”二值抽象。它是连接芯片内部逻辑与外部物理世界的桥梁,直接决…...
终极算法可视化指南:通过cp-algorithms项目直观理解复杂数据结构与算法过程
终极算法可视化指南:通过cp-algorithms项目直观理解复杂数据结构与算法过程 【免费下载链接】cp-algorithms Algorithm and data structure articles for https://cp-algorithms.com (based on http://e-maxx.ru) 项目地址: https://gitcode.com/GitHub_Trending/…...
STM32中断优先级科普:以F103为例,从零吃透NVIC分组与实战配置
前言 STM32F103作为入门级嵌入式开发的经典款MCU,凭借性价比高、资料丰富、外设齐全的特点,成为绝大多数嵌入式新手的第一块开发板。不管是按键外部中断、串口收发、定时器定时,还是ADC采集、SPI通信,都会用到中断机制;…...
