FreeRTOS源码分析-10 互斥信号量

目录

1 事件标志组概念及其应用

1.1 事件标志组定义

1.2 FreeRTOS事件标志组介绍

1.3 FreeRTOS事件标志组工作原理

2 事件标志组应用

2.1 功能需求

2.2 API

 2.3 功能实现

3 事件标志组原理

3.1 事件标志组控制块

3.2 事件标志组获取标志位

3.3 等待事件标志触发

3.4 事件标志组设置标志位

3.5 事件标志组任务同步


1 事件标志组概念及其应用

1.1 事件标志组定义

门钥匙代表或的问题,每个都可以开启
公交车代表与的问题,到齐了才可以走

 

FreeRTOS事件标志组一共8个bit。

如Task 1或Tast 2去触发第1位,第1位或第三位能触发任务Task3

如Task 6、7、8同时置位触发Task 4

1.2 FreeRTOS事件标志组介绍

任务可以和事件标志组进行关联,如bit23,任务阻塞等待消息,和消息队列一样有个超时机制

当任意任务或者中断触发置位的时候,任务会从阻塞变为就绪态。

1.3 FreeRTOS事件标志组工作原理

 创建事件控制块,关联事件,等待事件触发

2 事件标志组应用

2.1 功能需求

  • 1、使用事件标志组检测多个按键输入(K3、K4、K5、K6)
  • 2、当检测到任何一个按键按下,串口打印输出按键信息
  • 3、当4路按键都已经按下,触发蜂鸣器报警

2.2 API

CubeMX中未提供,需要自己创建

 EventBits_t 返回值返回的是所有24位的值

守护任务:处理操作系统不想在中断中处理的任务,是一种特殊类型的任务,它在系统中扮演着重要的角色。它被用于监控和处理FreeRTOS内部的错误和异常情况,以确保系统的稳定性。守护任务可以使用软件定时器来执行一些周期性的任务。通过创建一个周期性的软件定时器,守护任务可以在固定的时间间隔内执行特定的操作。例如,守护任务可以使用软件定时器来定期检查任务堆栈的使用情况、检测任务优先级错误或处理未处理的中断等。软件定时器提供了一种简便的方式来触发守护任务的执行,以确保系统中的重要任务得到及时处理。

中断中不允许上下文切换,都是由守护任务来执行的。

 使用WaitBits,会让任务进入阻塞态

 参数解释:

  • xEventGroup:事件组句柄,表示要操作的事件组。
  • uxBitsToWaitFor:等待的事件位,即需要等待其中的哪些事件发生。可以使用位掩码形式指定多个事件位。若指定为0,则表示不等待任何事件,直接返回当前事件组的位状态。
  • uxBitsToSet:设置的事件位,即在等待期间发生事件后,需要设置哪些事件位。同样,可以使用位掩码指定多个事件位。
  • xTicksToWait:等待的超时时间,以FreeRTOS的Tick单位表示。可以设置为portMAX_DELAY表示无限等待,或者具体的等待时间。

返回值:

  • 返回已经发生的事件位,即满足等待条件的事件。如果等待发生事件时超时,则返回0。

使用xEvetnGroupSync函数的具体步骤如下:

  1. 创建或获取一个事件组句柄。
  2. 使用xEvetnGroupSync函数等待指定的事件位。可以设置需要等待的事件位、需要设置的事件位和等待超时时间。
  3. 根据返回值判断等待是否成功,根据已发生的事件位执行相应的操作。

注意,xEvetnGroupSync函数是一个阻塞函数,即在等待期间会阻塞当前任务的执行。如果有其他任务在等待相同的事件组,则它们可能会被唤醒以执行后续操作。因此,在使用xEvetnGroupSync函数时需要谨慎设计,以避免出现死锁或优先级反转等问题。

 2.3 功能实现

STM32CubeMX功能配置

GPIO略

根据接口说明 ,事件标志组中断中需要开启守护任务

 

 

 

按键中断及事件标志组创建

//freertos.c//...略
#include "event_groups.h"EventGroupHandle_t KeyEventGroup; //全局变量句柄void MX_FREERTOS_Init(void) {//创建KeyEventGroup = xEventGroupCreate();if(KeyEventGroup == NULL){printf("KeyEventGroup Create Error\r\n");}//...略
}

按键检测任务和蜂鸣器报警任务

 

//gpio.c#include "event_groups.h"//...略
/*  
#define KEY3_EVENT_BIT  (1<<0)
#define KEY4_EVENT_BIT  (1<<1)
#define KEY5_EVENT_BIT  (1<<2)
#define KEY6_EVENT_BIT  (1<<3) typedef enum
{KEY_DOWN,KEY_UP,KEY_RESET}teKeyStatus;*/teKeyStatus KeyStatus;
extern EventGroupHandle_t KeyEventGroup;void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){if(Key3_Pin == GPIO_Pin){if(HAL_GPIO_ReadPin(Key3_GPIO_Port,Key3_Pin) == GPIO_PIN_RESET){HAL_Delay(10);if(HAL_GPIO_ReadPin(Key3_GPIO_Port,Key3_Pin) == GPIO_PIN_RESET){//设置事件xEventGroupSetBitsFromISR(KeyEventGroup,KEY3_EVENT_BIT,NULL);}}}if(Key4_Pin == GPIO_Pin){if(HAL_GPIO_ReadPin(Key4_GPIO_Port,Key4_Pin) == GPIO_PIN_RESET){HAL_Delay(10);if(HAL_GPIO_ReadPin(Key4_GPIO_Port,Key4_Pin) == GPIO_PIN_RESET){//设置事件xEventGroupSetBitsFromISR(KeyEventGroup,KEY4_EVENT_BIT,NULL);}}}if(Key5_Pin == GPIO_Pin){if(HAL_GPIO_ReadPin(Key5_GPIO_Port,Key5_Pin) == GPIO_PIN_RESET){HAL_Delay(10);if(HAL_GPIO_ReadPin(Key5_GPIO_Port,Key5_Pin) == GPIO_PIN_RESET){//设置事件xEventGroupSetBitsFromISR(KeyEventGroup,KEY5_EVENT_BIT,NULL);}}}if(Key6_Pin == GPIO_Pin){if(HAL_GPIO_ReadPin(Key6_GPIO_Port,Key6_Pin) == GPIO_PIN_RESET){HAL_Delay(10);if(HAL_GPIO_ReadPin(Key6_GPIO_Port,Key6_Pin) == GPIO_PIN_RESET){//设置事件xEventGroupSetBitsFromISR(KeyEventGroup,KEY6_EVENT_BIT,NULL);}}}
}
//freertos.cvoid Delay_Task(void const * argument)
{/* USER CODE BEGIN Delay_Task */EventBits_t KeyEventBits;/* Infinite loop */for(;;){KeyEventBits = xEventGroupWaitBits(KeyEventGroup,KEY3_EVENT_BIT|KEY4_EVENT_BIT|KEY5_EVENT_BIT|KEY6_EVENT_BIT,pdFALSE,pdFALSE,portMAX_DELAY);printf("Key is Down Key Event Bit is %x\r\n",KeyEventBits);osDelay(10);}
}void High_Task(void const * argument)
{EventBits_t KeyEventBits;for(;;){KeyEventBits = xEventGroupWaitBits(KeyEventGroup,KEY3_EVENT_BIT|KEY4_EVENT_BIT|KEY5_EVENT_BIT|KEY6_EVENT_BIT,pdTRUE,pdTRUE,portMAX_DELAY);	if(KeyEventBits == (KEY3_EVENT_BIT|KEY4_EVENT_BIT|KEY5_EVENT_BIT|KEY6_EVENT_BIT)){printf("Buzzer is Toggle\r\n");HAL_GPIO_TogglePin(Buzzer_GPIO_Port,Buzzer_Pin);}osDelay(10);}
}

3 事件标志组原理

3.1 事件标志组控制块

 

#define eventCLEAR_EVENTS_ON_EXIT_BIT	0x01000000UL		//表示退出是否清楚已经触发的标志位 25bit表示#define eventUNBLOCKED_DUE_TO_BIT_SET	0x02000000UL		//解除阻塞是否,已经设置标志位 26位#define eventWAIT_FOR_ALL_BITS			0x04000000UL		//是与逻辑还是或逻辑#define eventEVENT_BITS_CONTROL_BYTES	0xff000000UL		//用于分解出,事件标志组位使用typedef struct xEventGroupDefinition
{//事件标志组EventBits_t uxEventBits;//任务等待的列表List_t xTasksWaitingForBits;		/*< List of tasks waiting for a bit to be set. */
} EventGroup_t;

3.2 事件标志组获取标志位

 全局变量一定要保护,所以要进入临界段

#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )/*参数:1、控制块/句柄2、要清除位返回值:事件标志位*/ 1<<0
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
{
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn;/*1、进入临界段2、获取当前事件标志位3、清除要设置的事件标志位4、退出临界段5、返回事件标志组值*/taskENTER_CRITICAL();{/* The value returned is the event group value prior to the bits beingcleared. */uxReturn = pxEventBits->uxEventBits;/* Clear the bits. */pxEventBits->uxEventBits &= ~uxBitsToClear;}taskEXIT_CRITICAL();return uxReturn;
}/*参数:	1、事件控制块返回值:事件标志位*/
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
{
UBaseType_t uxSavedInterruptStatus;
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn;//禁止中断 带返回值uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();{//获取事件标志位uxReturn = pxEventBits->uxEventBits;}//恢复中断,在进入禁止之前的状态portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );return uxReturn;
}

3.3 等待事件标志触发

 复位列表项:表示事件信息

/*参数:1、事件控制块2、要等待出发的标志位3、退出是否要清除4、与逻辑还是或逻辑5、阻塞等待时间返回值:当前事件标志位
*/
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
{
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn, uxControlBits = 0;
BaseType_t xWaitConditionMet, xAlreadyYielded;
BaseType_t xTimeoutOccurred = pdFALSE;//挂起调度器vTaskSuspendAll();{//获取当前的事件标志位const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;/* 检查是否触发 参数:	1、当前的事件标志位2、要等待触发的事件标志位3、触发逻辑???返回值:	pdFALSE  pdTRUE*/xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );if( xWaitConditionMet != pdFALSE ){/* 已经触发 */uxReturn = uxCurrentEventBits;xTicksToWait = ( TickType_t ) 0;/* 清楚已经触发的标志 */if( xClearOnExit != pdFALSE ){pxEventBits->uxEventBits &= ~uxBitsToWaitFor;}else{mtCOVERAGE_TEST_MARKER();}}else if( xTicksToWait == ( TickType_t ) 0 ){/* 不需要超时,直接返回标志位. */uxReturn = uxCurrentEventBits;}else{/* 事件没有触发,并且需要超时*/if( xClearOnExit != pdFALSE ){//uxControlBits = 0x01000000UL;uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;}else{mtCOVERAGE_TEST_MARKER();}if( xWaitForAllBits != pdFALSE ){//uxControlBits = 0x05000000UL;uxControlBits |= eventWAIT_FOR_ALL_BITS;}else{mtCOVERAGE_TEST_MARKER();}/* 把任务添加到事件列表中参数:1、列表的地址2、传入列表项值3、任务阻塞时间*/vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );uxReturn = 0;traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );}}//恢复调度器xAlreadyYielded = xTaskResumeAll();//再次判断是否需要超时if( xTicksToWait != ( TickType_t ) 0 ){if( xAlreadyYielded == pdFALSE ){//进行上下文切换 ->pendSVportYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}/* 任务已经恢复1、复位列表项中的值  复位为任务有优先级*/uxReturn = uxTaskResetEventItemValue();//是不是通过事件置位解除的任务if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ){//进入临界段taskENTER_CRITICAL();{/* 获取当前事件位. */uxReturn = pxEventBits->uxEventBits;/* 再此判断是否已经置位 */if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE ){//如果需要清除,清除触发后的标志位if( xClearOnExit != pdFALSE ){pxEventBits->uxEventBits &= ~uxBitsToWaitFor;}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}taskEXIT_CRITICAL();xTimeoutOccurred = pdFALSE;}else{/* The task unblocked because the bits were set. */}/* 返回当前事件标志位. */uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;}traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );return uxReturn;
}

3.4 事件标志组设置标志位

 

/*参数:1、事件控制块2、要设置的事件位返回值:1、当前事件标志位
*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
{
ListItem_t *pxListItem, *pxNext;
ListItem_t const *pxListEnd;
List_t *pxList;
EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
BaseType_t xMatchFound = pdFALSE;//获取事件列表头pxList = &( pxEventBits->xTasksWaitingForBits );//获取列表尾节点pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. *///挂起调度器vTaskSuspendAll();{//获取头节点pxListItem = listGET_HEAD_ENTRY( pxList );/* 设置事件标志位 */pxEventBits->uxEventBits |= uxBitsToSet;/* 循环遍历整个列表项,直到列表头节点等于尾节点(指针) */while( pxListItem != pxListEnd ){//获取下个列表项pxNext = listGET_NEXT( pxListItem );//获取当前列表项的值uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem );//标记,是否找到需要处理的节点xMatchFound = pdFALSE;/* 拆分*/uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 ){//或逻辑/* 等待位已经置位 */if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 ){//找到了已经触发的节点xMatchFound = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}//表示所有等待的位都已经触发else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor ){/*找到触发的节点 */xMatchFound = pdTRUE;}else{/* Need all bits to be set, but not all the bits were set. */}if( xMatchFound != pdFALSE ){/* 是否需要清除 */if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 ){//做个标记uxBitsToClear |= uxBitsWaitedFor;}else{mtCOVERAGE_TEST_MARKER();}/* 把任务从事件列表中移除参数:	1、列表项2、事件标志位+解锁处理标志位  内部写入了列表项的value里面*/( void ) xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );}/* 当前列表项指向下个,继续遍历*/pxListItem = pxNext;}/* 清除设置后的标志位 */pxEventBits->uxEventBits &= ~uxBitsToClear;}//开启调度器( void ) xTaskResumeAll();return pxEventBits->uxEventBits;
}/*参数:1、事件控制块2、要设置的标志位3、NULL*/BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ){BaseType_t xReturn;//调用软件定时器函数,,用于发送消息到软件定时器任务,进行处理xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken );return xReturn;}/*设置事件标志位的回调函数,内部其实就是调用xEventGroupSetBits*/void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ){( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet );}BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken ){DaemonTaskMessage_t xMessage;BaseType_t xReturn;/* 封装消息 */xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR;xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;//通过消息队列和软件定时器任务进行通信xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );/*分析:软件定时器任务要等待消息队列,之后解析处理,最终调用xEventGroupSetBits*/return xReturn;}

3.5 事件标志组任务同步

 待完成

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

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

相关文章

小程序的api使用 以及一些weui组件实列获取头像 扫码等

今日目标 响应式单位rpx小程序的生命周期 【重点】20%小程序框架 weui 【重点】 50%内置API 【重点】30%综合练习 1. 响应式rpx 1.1 rpx单位 rpx是微信小程序提出的一个尺寸单位&#xff0c;将整个手机屏幕宽度分为750份&#xff0c;1rpx 就是 1/750&#xff0c;避免不同手…

QT自带PDF库的使用

QT自带PDF库可以方便的打开PDF文件&#xff0c;并将文件解析为QImage&#xff0c;相比网上提供的开源库&#xff0c;QT自带PDF库使用更方便&#xff0c;也更加可靠&#xff0c;然而&#xff0c;QT自带PDF库的使用却不同于其他通用库的使用&#xff0c;具备一定的技巧。 1. 安装…

以太网DHCP协议(十)

目录 一、工作原理 二、DHCP报文 2.1 DHCP报文类型 2.2 DHCP报文格式 当网络内部的主机设备数量过多是&#xff0c;IP地址的手动设置是一件非常繁琐的事情。为了实现自动设置IP地址、统一管理IP地址分配&#xff0c;TCPIP协议栈中引入了DHCP协议。 一、工作原理 使用DHCP之…

通向架构师的道路之weblogic与apache的整合与调优

一、BEAWeblogic的历史 BEA WebLogic是用于开发、集成、部署和管理大型分布式Web应用、 网络应用和数据库应 用的Java应用服务器。将Java的动态功能和Java Enterprise标准的安全性引入大型网络应用的 开发、集成、部署和管理之中。 BEA WebLogic Server拥有处理关键Web应…

pytorch求导

pytorch求导的初步认识 requires_grad tensor(data, dtypeNone, deviceNone, requires_gradFalse)requires_grad是torch.tensor类的一个属性。如果设置为True&#xff0c;它会告诉PyTorch跟踪对该张量的操作&#xff0c;允许在反向传播期间计算梯度。 x.requires_grad 判…

TM4C123库函数学习(1)--- 点亮LED+TM4C123的ROM函数简介+keil开发环境搭建

前言 &#xff08;1&#xff09; 首先&#xff0c;我们需要知道TM4C123是M4的内核。对于绝大多数人而言&#xff0c;入门都是学习STM32F103&#xff0c;这款芯片是采用的M3的内核。所以想必各位对M3内核还是有一定的了解。M4内核就是M3内核的升级版本&#xff0c;他继承了M3的的…

【力扣每日一题】2023.8.5 合并两个有序链表

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们两个有序的链表&#xff0c;要我们保持升序的状态合并它们。 我们可以马上想要把两个链表都遍历一遍&#xff0c;把所有节点的…

1-搭建一个最简单的验证平台UVM,已用Questasim实现波形!

UVM-搭建一个最简单的验证平台&#xff0c;已用Questasim实现波形 1&#xff0c;背景知识2&#xff0c;".sv"文件搭建的UVM验证平台&#xff0c;包括代码块分享3&#xff0c;Questasim仿真输出&#xff08;1&#xff09;compile all&#xff0c;成功&#xff01;&…

【力扣每日一题】2023.8.8 任意子数组和的绝对值的最大值

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一个数组&#xff0c;让我们找出它的绝对值最大的子数组的和。 这边的子数组是要求连续的&#xff0c;让我们找出一个元素之和…

GG修改器安装与Root环境的安装

关于GG修改器大家应该都有一定的了解吧&#xff0c;就是类似于电脑端CE的一个软件。 GG修改器在百度云盘里请自行下载&#xff01; 百度网盘链接&#xff1a;https://pan.baidu.com/s/1p3KJRg9oq4s0XzRuEIBH4Q 提取码&#xff1a;vuwj 那我要开始了&#xff01; 本来不想讲GG…

Spring Boot集成EasyPoi实现导入导出操作

文章目录 Spring Boot集成EasyPoi实现导入导出操作0 简要说明1 环境搭建1.1 项目目录1.2 依赖管理2.3 关于swagger处理2.4 关于切面处理耗时1 自定义注解2 定义切面类3 如何使用 2.5 核心导入操作2.6 核心导出操作 2 最佳实线2.1 导入操作1 实体类说明2 业务层3 效果3 控制层 2…

常用抓包工具

Fiddler Fiddler 是一个很好用的抓包工具&#xff0c;可以用于抓取http/https的数据包&#xff0c;常用于Windows系统的抓包&#xff0c;它有个优势就是免费 Charles Charles是由JAVA开发的&#xff0c;可以运行在window Linux MacOS&#xff0c;但它是收费的&#xff0c;和…

httpd+Tomcat(jk)的Web动静分离搭建

动静分离是指将动态请求和静态请求分别交给不同的服务器来处理&#xff0c;可以提高服务器的效率和性能。在Java Web开发中&#xff0c;常见的动态请求处理方式是通过Tomcat来处理&#xff0c;而静态请求则可以通过Apache服务器来处理。本文将详细讲解如何结合Apache和Tomcat来…

面试热题(翻转k个链表)

给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改变节点内部的值&a…

ctfshow-web7

0x00 前言 CTF 加解密合集 CTF Web合集 0x01 题目 0x02 Write Up 通过尝试&#xff0c;发现是数字型的注入&#xff0c;并且同样是过滤了空格 判断字段 获取一下flag即可 1/**/union/**/select/**/1,flag,3/**/from/**/web7.flag#&passworda以上

Spring接口ApplicationRunner的作用和使用介绍

在Spring框架中&#xff0c;ApplicationRunner接口是org.springframework.boot.ApplicationRunner接口的一部分。它是Spring Boot中用于在Spring应用程序启动完成后执行特定任务的接口。ApplicationRunner的作用是在Spring应用程序完全启动后&#xff0c;执行一些初始化任务或处…

【框架篇】MyBatis 介绍及使用(详细教程)

一&#xff0c;MyBatis 介绍 MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff…

Oracle以逗号分隔的字符串拆分为多行数据实例详解

前言 近期在工作中遇到某表某字段是可扩展数据内容&#xff0c;信息以逗号分隔生成的&#xff0c;现需求要根据此字段数据在其它表查询相关的内容展现出来&#xff0c;第一想法是切割数据&#xff0c;以逗号作为切割符&#xff0c;以下为总结的实现方法&#xff0c;以供大家参…

微服务 云原生:基于 Gogs + Drone 进行项目 CI/CD

传统构建部署 以一个简单的前后端项目来说&#xff0c;分别编写前后端的 Dockerfile 文件并构建镜像&#xff0c;然后编写 docker-compose.yml 构建部署&#xff0c;启动运行。 一个简单的例子&#xff1a; 前端&#xff1a; 项目名&#xff1a;kubemanagement-web技术栈&am…

tomcat配置文件和web站点部署(zrlog)简介

一.tomcat/apache-tomcat-8.5.70/conf/server.xml组件类别介绍 1.类别 2.Connector参数 3.host参数 4.Context参数 二.web站点部署(以zrlog为例) 1.将zrlog的war包传到webapps下面 2.在mysql数据库中创建zrlog用户并赋予权限 3.完成安装向导&#xff0c;登录管理界面即可…