FreeRTOS(事件组)

 资料来源于硬件家园:资料汇总 - FreeRTOS实时操作系统课程(多任务管理)

目录

一、事件的概念与应用 

1、事件的概念

2、事件的应用

二、事件的运作机制

1、FreeRTOS中事件组的句柄

2、FreeRTOS 任务间事件标志组的实现

3、FreeRTOS 中断方式事件标志组的实现

三、事件的API函数‍

 1、事件的典型流程与API

2、事件组创建与删除

3、任务内置位事件组

4、中断内置位事件组

5、等待事件组

四、事件的应用 - 任务与任务

1、任务配置

2、创建事件组

3、按键任务部分代码

4、同步任务代码

五、事件的应用 - 中断与任务

1、任务配置

2、开启FreeRTOS软件定时器

3、创建事件组

4、同步任务代码

5、串口回调函数代码

一、事件的概念与应用 

1、事件的概念

事件是实现任务与任务或任务与中断间通信的机制,用于同步,无数据传输。

与信号量不同的是,事件可以实现一对多、多对多的同步,即一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理。同样,也可以是多个任务同步多个事件。

FreeRTOS提供的事件具有如下特点:

① 事件相互独立,一个32位的事件集合(EventBitst类型的变量,实际可用于表示事件的只有低24位)用于标识该任务发生的事件类型,其中每一位表示一种事件类型(0表示该事件类型未发生,1表示该事件类型已经发生),一共有 24种事件类型。

②事件仅用于同步,不提供数据传输功能。

③ 事件无排队性,即多次向任务设置同一事件(如果任务还未来得及读取),等效于只设置一次。

④允许多个任务对同一事件进行读写操作。

⑤ 支持事件等待超时机制。

在FreeRTOS 事件中,获取每个事件时,用户可以选择感兴趣的事件,并且选择读取事件信息标记。它有3个属性,分别是逻辑与、逻辑或以及是否清除标记。当任务等待事件同步时,可以通过任务感兴趣的事件位和事件信息标记来判断当前接收的事件是否满足要求,如果满足,则说明任务等到对应的事件,系统将唤醒等待的任务;否则,任务会根据用户指定的阻塞超时时间继续等待下去。

2、事件的应用

FrecRTOS的事件用于任务与任务或任务与中断间的同步。为什么不直接用变量呢?那样岂不是更有效率?若是在裸机编程中,用全局变量是最有效的方法,但是在操作系统中,使用全局变量就要考虑以下问题了:

①如何对全局变量进行保护?如何处理多任务同时对它进行访问的情况?

②如何让内核对事件进行有效管理?

如果使用全局变量,就需要在任务中轮询查看事件是否发送,这会造成CPU 资源的浪费,此外,用户还需要自己去实现等待超时机制。所以,在操作系统中最好还是使用系统提供的通信机制,简单、方便、实用。

在某些场合,可能需要多个事件发生后才能进行下一步操作,比如一些危险机器的启动,需要检查各项指标,当指标不达标时就无法启动。但是检查各个指标时,不会立刻检测完毕,所以需要事件来做统一的等待。当所有的事件都完成了,那么机器才允许启动,这只是事件的应用之一

事件可用于多种场合,能够在一定程度上替代信号量,用于任务与任务间、中断与任务间的同步。一个任务或中断服务例程发送一个事件给事件对象,而后等待的任务被唤醒并对相应的事件进行处理。但是事件与信号量不同的是,事件的发送操作是不可累计的,而信号量的释放动作是可累计的。事件的另外一个特性是,接收任务可等待多种事件,即多个事件对应一个任务或多个任务。同时按照任务等待的参数,可选择是“逻辑或”触发还是“逻辑与”触发。这个特性也是信号量等所不具备的,信号量只能识别单一同步动作,而不能同时等待多个事件的同步。

各个事件可分别发送或一起发送给事件对象,而任务可以等待多个事件,任务仅对感兴趣的事件进行关注。当有它们感兴趣的事件发生并且符合条件时,任务将被唤醒并进行后续的处理动作。

二、事件的运作机制

1、FreeRTOS中事件组的句柄

图片

uxEventBits: 对于STM32,此变量为32位,其中低24位用于事件位,高8位用于其他用途。

图片

2、FreeRTOS 任务间事件标志组的实现

任务间事件标志组的实现是指各个任务之间使用事件标志组实现任务的同步机制。

下面的框图说明FreeRTOS 事件标志的实现:

图片

运行条件: 创建 2 个任务:Task1 和 Task2

运行过程描述如下:

 任务 Task1 运行过程中调用函数 xEventGroupWaitBits,等待事件标志位被设置,任务 Task1 由运行态进入到阻塞态。

 任务 Task2 设置 Task1 等待的事件标志,任务 Task1 由阻塞态进入到就绪态,在调度器的作用下由就绪态又进入到运行态。

上面就是一个简单的 FreeRTOS 任务间事件标志通信过程。

3、FreeRTOS 中断方式事件标志组的实现

FreeRTOS 中断方式事件标志组的实现是指中断函数和 FreeRTOS 任务之间使用事件标志。

下面的框图说明FreeRTOS 事件标志的实现:

图片

运行条件: 创建一个任务和一个串口接收中断

运行过程描述如下:

 任务 Task1 运行过程中调用函数 xEventGroupWaitBits,等待事件标志位被设置,任务 Task1 由运行态进入到阻塞态。

 Task1 阻塞的情况下,串口接收到数据进入到了串口中断服务程序,在串口中断服务程序中设置 Task1等待的事件标志,任务 Task1 由阻塞态进入到就绪态,在调度器的作用下由就绪态又进入到运行态。

上面就是一个简单的 FreeRTOS 中断方式事件标志通信过程。

实际应用中,中断方式的消息机制要注意以下三个问题:

 中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应。

 实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在任务中实现消息处理,这样可以有效地保证中断服务程序的实时响应。同时此任务也需要设置为高优先级,以便退出中断函数后任务可以得到及时执行。

 中断服务程序中一定要调用专用于中断的事件标志设置函数,即以 FromISR 结尾的函数。

三、事件的API函数‍

 1、事件的典型流程与API

> 创建事件组  xEventGroupCreate()

> 置位事件组  xEventGroupSetBits() , xEventGroupSetBitsFromISR()

> 等待事件组  xEventGroupWaitBits()

> 删除事件组  vEventGroupDelete()

2、事件组创建与删除

>事件组控制块(句柄)

图片

uxEventBits: 对于STM32,此变量为32位,其中低24位用于事件位

xTasksWaitingForBits: 任务等待链表

图片

>创建事件组

函数原型:EventGroupHandle_t xEventGroupCreate( void );

函数描述:函数 xEventGroupCreate 用于创建事件标志组。

 返回值,如果创建成功,此函数返回事件标志组的句柄,如果 FreeRTOSConfig.h 文件中定义的 heap空间不足会返回 NULL

使用举例:

图片

>删除事件组

函数原型:vEventGroupDelete(EventGroupHandle_t xEventGroup);

函数描述:函数 vEventGroupDelete可用于删除事件组。 

3、任务内置位事件组

函数原型:EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,

                                                                                         const EventBits_t uxBitsToSet );

函数描述:函数 xEventGroupSetBits 用于设置指定的事件标志位为 1。

 第 1 个参数是事件标志组句柄。

 第 2 个参数表示 24 个可设置的事件标志位,EventBits_t 是定义的 32 位变量,低 24 位用于事件标志设置。变量 uxBitsToSet 的低 24 位的某个位设置为 1,那么被设置的事件标志组的相应位就设置为 1。变量 uxBitsToSet 设置为 0 的位对事件标志相应位没有影响。比如设置变量 uxBitsToSet = 0x0003 就表示将事件标志的位 0 和位 1 设置为 1,其余位没有变化。

 返回当前的事件标志组数值。

使用这个函数要注意以下问题:

1. 使用前一定要保证事件标志组已经通过函数 xEventGroupCreate 创建了。

2. 此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是xEventGroupSetBitsFromISR

3. 用户通过参数 uxBitsToSet 设置的标志位并不一定会保留到此函数的返回值中,下面举两种情况:

a. 调用此函数的过程中,其它高优先级的任务就绪了,并且也修改了事件标志,此函数返回的事件标志位会发生变化。

b. 调用此函数的任务是一个低优先级任务,通过此函数设置了事件标志后,让一个等待此事件标志的高优先级任务就绪了,会立即切换到高优先级任务去执行,相应的事件标志位会被函数

xEventGroupWaitBits 清除掉,等从高优先级任务返回到低优先级任务后,函数

xEventGroupSetBits 的返回值已经被修改。

使用举例:

图片

4、中断内置位事件组

函数原型:BaseType_t xEventGroupSetBitsFromISR(EventGroupHandle_t xEventGroup,

                                                                                             const EventBits_t uxBitsToSet, 

                                                                                  BaseType_t *pxHigherPriorityTaskWoken );

函数描述:函数 xEventGroupSetBits 用于设置指定的事件标志位为 1。

 第 1 个参数是事件标志组句柄。

 第 2 个参数表示 24 个可设置的事件标志位,EventBits_t 是定义的 32 位变量,低 24 位用于事件标志设置。变量 uxBitsToSet 的低 24 位的某个位设置为 1,那么被设置的事件标志组的相应位就设置为 1。变量 uxBitsToSet 设置为 0 的位对事件标志相应位没有影响。比如设置变量 uxBitsToSet = 0x0003 就表示将事件标志的位 0 和位 1 设置为 1,其余位没有变化。

 第 3 个参数用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是 pdTRUE,说明有高优先级任务要执行,否则没有。

 返回值,如果消息成功发送给守护任务(就是FreeRTOS 的定时器服务任务)返回 pdPASS,否则返回 pdFAIL,另外守护任务中的消息队列满了也会返回 pdFAIL。

使用这个函数要注意以下问题:

1. 使用前一定要保证事件标志已经通过函数 xEventGroupCreate 创建了。同时要在 FreeRTOSConfig.h

文件中使能如下三个宏定义:

#define INCLUDE_xEventGroupSetBitFromISR 1

#define configUSE_TIMERS 1

#define INCLUDE_xTimerPendFunctionCall 1

2. 函数 xEventGroupSetBitsFromISR 是用于中断服务程序中调用的,故不可以在任务代码中调用此函数,任务代码中使用的是 xEventGroupSetBits。

3. 函数 xEventGroupSetBitsFromISR 对事件标志组的操作是不确定性操作,因为不知道当前有多少个任务在等待此事件标志。而 FreeRTOS 不允许在中断服务程序和临界段中执行不确定性操作。为了不在中断服务程序中执行,就通过此函数给 FreeRTOS 的守护任务(就是 FreeRTOS 的定时器服务任务,内核自动创建的)发送消息,在守护任务中执行事件标志的置位操作。同时也为了不在临界段中执行此不确定操作,将临界段改成由调度锁来完成。这样不确定性操作在中断服务程序和临界段中执行的问题就都得到解决了。

4. 由于函数 xEventGroupSetBitsFromISR 对事件标志的置位操作是在守护任务里面执行的,如果想让置位操作立即生效,即让等此事件标志的任务能够得到及时执行,需要设置守护任务的优先级高于使用此事件标志组的所有其它任务。

使用举例:

图片

5、等待事件组

函数原型:

EventBits_t xEventGroupWaitBits(

        const EventGroupHandle_t xEventGroup, /* 事件标志组句柄 */

        const EventBits_t uxBitsToWaitFor, /* 等待被设置的事件标志位 */

        const BaseType_t xClearOnExit, /* 选择是否清零被置位的事件标志位 */

        const BaseType_t xWaitForAllBits, /* 选择是否等待所有标

        TickType_t xTicksToWait ); /* 设置等待时间 */

函数描述:

函数 xEventGroupWaitBits 等待事件标志被设置。

 第 1 个参数是事件标志组句柄。

 第 2 个参数表示等待 24 个事件标志位中的指定标志,EventBits_t 是定义的 32 位变量,低 24 位用于事件标志设置。比如设置变量 uxBitsToWaitFor = 0x0003 就表示等待事件标志的位 0 和位 1 设置为 1。此参数切不可设置为 0。

 第 3 个参数选择是否清除已经被置位的事件标志,如果这个参数设置为 pdTRUE,且函数

xEventGroupWaitBits 在参数 xTicksToWait 设置的溢出时间内返回或等到满足任务唤醒的事件时,相应被设置的事件标志位会被清零。如果这个参数设置为 pdFALSE,对已经被设置的事件标志位没有影响。

 第 4 个参数选择是否等待所有的标志位都被设置,如果这个参数设置为 pdTRUE,要等待第 2 个参数 uxBitsToWaitFor 所指定的标志位全部被置 1,函数才可以返回。当然,超出了在参数xTicksToWait 设置的溢出时间也是会返回的。如果这个参数设置为 pdFALSE,第 2 个参数uxBitsToWaitFor 所指定的任何标志位被置 1,函数都会返回,超出溢出时间也会返回。

 第 5 个参数设置等待时间,单位时钟节拍周期。如果设置为 portMAX_DELAY,表示永久等待。

 返回值,由于设置的时间超时或者指定的事件标志位被置 1,导致函数退出时返回的事件标志组数值。

使用这个函数要注意以下问题:

1. 此函数切不可在中断服务程序中调用。

2. 着重说明下这个函数的返回值,通过返回值用户可以检测是哪个事件标志位被置 1 了

 如果由于设置的等待时间超时,函数的返回值可会有部分事件标志位被置 1。

 如果由于指定的事件标志位被置1而返回,并且设置了这个函数的参数xClearOnExit为pdTRUE,那么此函数的返回值是清零前的事件标志组数值。

另外,调用此函数的任务在离开阻塞状态到退出函数 xEventGroupWaitBits 之间这段时间,如果一个高优先级的任务抢占执行了,并且修改了事件标志位,那么此函数的返回值会跟当前的事件标志组数值不同。

使用举例:

图片

四、事件的应用 - 任务与任务

1、任务配置

LED0_Task: 运行指示灯

KEY_Task: 按键,打印任务信息,触发事件

Event_Sync_Task:   等待事件,同步任务

2、创建事件组

定义

/* USER CODE BEGIN Variables */
EventGroupHandle_t MyEvent01Handle=NULL; //不能配置,只能自己写
/* USER CODE END  Variables */

创建

  /* USER CODE BEGIN Init */MyEvent01Handle = xEventGroupCreate();if(MyEvent01Handle==NULL){sprintf(buff,"%s \r\n","创建事件组失败");HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);}else{sprintf(buff,"%s \r\n","创建事件组成功");HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);}/* USER CODE END Init */

3、设置事件

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define KEY0_EVENT  (EventBits_t)(0x0001 << 0)//设置事件掩码位0
#define KEY1_EVENT  (EventBits_t)(0x0001 << 8)//设置事件掩码位8
/* USER CODE END PD */

4、按键任务部分代码

	  //KEY0if(KeyCode==KEY0){sprintf(buff,"%s \r\n","触发 KEY0 事件");HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);xEventGroupSetBits(MyEvent01Handle, KEY0_EVENT);}//KEY1if(KeyCode==KEY1){sprintf(buff,"%s \r\n","触发 KEY1 事件");HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);xEventGroupSetBits(MyEvent01Handle, KEY1_EVENT);}

5、预编译宏

#define Event_WaitAllBits //预编译,看是否需要等待所有事件

6、同步任务代码

void Event_Sync_Task(void const * argument)
{/* USER CODE BEGIN Event_Sync_Task */EventBits_t xEvent;int  SyncCnt = 0; //同步计数/* Infinite loop */
#ifdef Event_WaitAllBitsfor(;;){sprintf(buff,"%s \r\n","等待事件同步信号,无限等待");HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);xEvent = xEventGroupWaitBits(MyEvent01Handle, //事件句柄KEY0_EVENT|KEY1_EVENT, //事件 按键0,1pdTRUE,          //退出时清除事件位pdTRUE,         //"逻辑或" - 满足任一事件portMAX_DELAY    //无限等待);if( (xEvent&(KEY0_EVENT|KEY1_EVENT)) == (KEY0_EVENT|KEY1_EVENT)){sprintf(buff,"成功接受到事件同步信号,次数 = %u\r\n",++SyncCnt);HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);}}
#elsefor(;;){sprintf(buff,"%s \r\n","等待事件同步信号,无限等待");HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);xEvent = xEventGroupWaitBits(MyEvent01Handle, //事件句柄KEY0_EVENT|KEY1_EVENT, //事件 按键0,1pdTRUE,          //退出时清除事件位pdFALSE,         //"逻辑或" - 满足任一事件portMAX_DELAY    //无限等待);if(((xEvent&KEY0_EVENT) == KEY0_EVENT) || ((xEvent&KEY1_EVENT) == KEY1_EVENT)){sprintf(buff,"成功接受到事件同步信号,次数 = %d\r\n",++SyncCnt);HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);}}
#endif/* USER CODE END Event_Sync_Task *//* USER CODE BEGIN BinarySem_Sync_Task */
}

五、事件的应用 - 中断与任务

1、任务配置

2、开启FreeRTOS软件定时器

 

3、创建事件组

同上任务与任务

4、同步代码

void Event_Sync_ISR_Task(void const * argument)
{/* USER CODE BEGIN Event_Sync_Task */EventBits_t xEvent;char rxBuff[13];/* Infinite loop */for(;;){//通过串口2中断接收12个字符HAL_UART_Receive_IT(&huart2, (uint8_t *)rxBuff, 12);sprintf(buff,"请通过UART2发送12个字符\r\n");HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);sprintf(buff,"等待事件同步信号,无限等待\r\n");HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);xEvent = xEventGroupWaitBits(MyEvent01Handle, //事件句柄UART2_RecEVENT,  //事件 - 串口3接收pdTRUE,          //退出时清除事件位pdTRUE,          //"逻辑与" - 满足所有事件portMAX_DELAY    //无限等待);if((xEvent&UART2_RecEVENT) == UART2_RecEVENT){sprintf(buff,"接收到的串口数据:%s\r\n\r\n",rxBuff);HAL_UART_Transmit(&huart2, (uint8_t*)buff,strlen(buff), HAL_MAX_DELAY);}HAL_UART_Receive_IT(&huart2, (uint8_t *)rxBuff, 12);}/* USER CODE END Event_Sync_Task */
}

5、串口回调函数代码

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{BaseType_t xHigherPriorityTaskWoken = pdFALSE;if(huart->Instance == huart2.Instance){xEventGroupSetBitsFromISR(MyEvent01Handle,UART2_RecEVENT,&xHigherPriorityTaskWoken);portYIELD_FROM_ISR(xHigherPriorityTaskWoken);}
}

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

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

相关文章

【多视重建】从Zero-123到One-2-3-45:多视角生成

文章目录 摘要一、引言二、相关工作三、Zero-1-to-33.1.学习如何控制照相机的视角3.2.视角作为条件的扩散3.3三维重构3.4 数据集 四、One-2-3-454.1 Zero123: 视角条件的 2D Diffusion4.2 NeRF优化&#xff1a;将多视图预测提升到三维图像4.3 基于不完美多视图的 神经表面重建*…

实训一 :Linux的启动、关机及登录

实训一 &#xff1a;Linux的启动、关机及登录 2017 年 2 月 22 日 今日公布 实训目标 完成本次实训&#xff0c;将能够&#xff1a; 描述Linux的开机过程。在图形模式和文本模式下登录Linux。关闭和重启Linux 实训准备 一台已安装RHEL6的虚拟计算机&#xff0c;Linux虚拟…

Node+MySQL+Vue2.0+elementUI实现的博客管理系统(一)

前端部分&#xff1a; Vue项目的入口文件main.js: //引入Vue import Vue from vue //引入App import App from ./App.vue //引入VueRouter import VueRouter from vue-router import router from ./router/index import Vuex from vuex import store from ./store //完整引入…

【字节跳动青训营】后端笔记整理-1 | Go语言入门指南:基础语法和常用特性解析

**本人是第六届字节跳动青训营&#xff08;后端组&#xff09;的成员。本文由博主本人整理自该营的日常学习实践&#xff0c;首发于稀土掘金&#xff1a;&#x1f517;Go语言入门指南&#xff1a;基础语法和常用特性解析 | 青训营 本文主要梳理自第六届字节跳动青训营&#xff…

护眼灯买哪种好,2023护眼台灯推荐

护眼台灯的光照一般比较均匀&#xff0c;相比普通台灯&#xff0c;一般具有防蓝光、防频闪等功能&#xff0c;能够提供一个健康舒适的学习、生活灯光环境&#xff0c;建议选购内置智能感光模式的护眼台灯&#xff0c;以确保灯光亮度一直处于均衡状态&#xff0c;让眼睛更轻松。…

谷歌关闭跨域限制.(生成一个开发浏览器),Chrome关闭跨域

(一)、首先找到浏览器在电脑磁盘中的位置,并复制 (二)、复制一个浏览器的快捷方式到桌面(不影响正常浏览器) (三)、chrom鼠标右键属性&#xff0c;修改快捷方式的目标 &#xff08;四&#xff09;chrome.exe 后面添加 --disable-web-security --user-data-dir 复制的Chrome浏览…

SpringBoot复习(39)Servlet容器的自动配置原理

Servlet容器自动配置类为ServletWebServerFactoryAutoConfiguration 可以看到通过Import注解导入了三个配置类&#xff1a; 通过这个这三个配置类可以看出&#xff0c;它们都使用了ConditionalOnClass注解&#xff0c;当类路径存在tomcat相关的类时&#xff0c;会配置一个T…

Jmeter 配置环境变量,简明教程专享

通过给 JMeter 配置环境变量&#xff0c;可以快捷的打开 JMeter&#xff1a; 打开终端。执行 jmeter。 配置环境变量的方法如下。 Mac 和 Linux 系统 在 ~/.bashrc 中加如下内容&#xff1a; export JMETER_HOMEJMeter所在目录 export PATH$JAVA_HOME/bin:$PATH:.:$JMETER…

使用阿里云服务器部署和使用GitLab

本文阿里云百科分享使用阿里云服务器部署和使用GitLab&#xff0c;GitLab是Ruby开发的自托管的Git项目仓库&#xff0c;可通过Web界面访问公开的或者私人的项目。本教程介绍如何部署和使用GitLab。 目录 准备工作 部署GitLab环境 使用GitLab 登录GitLab 生成密钥对文件并…

Netty:在一个ByteBuf中寻找另外一个ByteBuf出现的位置

说明 利用ByteBufUtil的indexOf(ByteBuf needle, ByteBuf haystack)函数可以在haystack中寻找needle出现的位置。如果没有找到&#xff0c;返回-1。 示例 在一个ByteBuf 中找到了另外一个ByteBuf package com.thb;import io.netty.buffer.ByteBuf; import io.netty.buffer.…

CDN(内容分发网络)

CDN的全称是 Content Delivery Network, 即内容分发网络。CDN是构建在现有网络基础之上的智能虚拟网络&#xff0c;依靠部署在各地的边缘服务器&#xff0c;通过中心平台的负载均衡、内容分发、调度等功能模块&#xff0c;使用户就近获取所需内容&#xff0c;降低网络拥塞&a…

图书馆管理系统、学生管理系统、交通管理系统(C语言、数据结构、java、Javaweb)

图书馆管理系统作为一个经典的项目&#xff0c;在国家、学校、等每个地方或者作为期末作品都用的非常广泛&#xff1a; C语言程序设计&#xff1a;图书馆管理系统含说明文档。 大一时C综合设计&#xff0c;当时得了96。代码纯原创&#xff0c;可直接运行&#xff0c;包含详细注…

nginx动态加载配置文件的方法

1. main函数调用ngx_get_options函数 2. ngx_get_options(int argc, char *const *argv)中会解析用户输入命令。 case ‘s’: if (*p) { ngx_signal (char *) p; } else if (argv[i]) {ngx_signal argv[i];} else {ngx_log_stderr(0, "option \"-s\" requi…

PHP流浪动物招领网站mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP流浪动物招领网站 是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 下载链接 nullhttps://download.csdn.net/download/qq_41221322/88190168视频演示 …

Web服务器项目一

文章目录 是什么HTTP协议——应用层协议服务器基本框架两种高效的处理模式线程池 是什么 Web服务器是一个服务器软件程序&#xff0c;主要功能是通过HTTP协议与客户端&#xff08;通常是浏览器Browser)进行通信&#xff0c;来接收&#xff0c;存储&#xff0c;处理来自客户端的…

ROS入门-第 1 章 ROS概述与环境搭建

目录 第 1 章 ROS概述与环境搭建 1.1 ROS简介 1.1.1 ROS概念 1.1.2 ROS设计目标 1.1.3 ROS发展历程 1.3 ROS快速体验 1.3.1 HelloWorld实现简介 1.3.2 HelloWorld&#xff08;C版&#xff09; 步骤 1&#xff1a;创建工作空间 步骤 2&#xff1a;创建发布者节点 步骤…

8.10 用redis实现缓存功能和Spring Cache

什么是缓存? 缓存(Cache), 就是数据交换的缓冲区,俗称的缓存就是缓冲区内的数据,一般从数据库中获取,存储于本地代码。 通过Redis来缓存数据&#xff0c;减少数据库查询操作; 逻辑 每个分类的菜品保存一份缓存数据 数据库菜品数据有变更时清理缓存数据 如何将商品数据缓存起…

DAY21

题目一 给定三个字符串str1、str2和aim&#xff0c; 如果aim包含且仅包含来自str1和str2的所有字符&#xff0c;而且在aim中属于str1的字符 之间保持原来在str1中的顺序&#xff0c;属于str2的字符之间保持原来在str2中的顺序&#xff0c;那么称aim是str1和str2的交错组成。实…

适配器模式:将不兼容的接口转换为可兼容的接口

适配器模式&#xff1a;将不兼容的接口转换为可兼容的接口 什么是适配器模式&#xff1f; 适配器模式是一种结构型设计模式&#xff0c;用于将一个类的接口转换为客户端所期望的另一个接口。它允许不兼容的类能够合作&#xff0c;使得原本由于接口不匹配而无法工作的类能够一…

IDEA常用设置与maven项目部署

目录 前言 一、Idea是什么 二、Idea的优点 三、Idea的常用设置 主题设置 设置鼠标悬浮提示 忽略大小写提示 自动导包 取消单行显示Tabs 设置字体 配置类文档注释信息模版 设置文件编码 设置自动编译 水平或者垂直显示代码 快捷方式改成eclipse 设置默认浏览器…