(学习日记)2024.03.12:UCOSIII第十四节:时基列表

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


点击此处进入学习日记的总目录

2024.03.12

  • 二十八、UCOSIII:时基列表
    • 1、实现时基列表
      • 1. 定义时基列表变量
      • 2. 修改任务控制块TCB
    • 2、实现时基列表相关函数
      • 1. OS_TickListInit()函数
      • 2. OS_TickListInsert()函数
      • 3. OS_TickListRemove()函数
      • 4. OS_TickListUpdate()函数
    • 3、修改OSTimeDly()函数
    • 4、修改OSTimeTick()函数

二十八、UCOSIII:时基列表

从本章开始,我们在OS中加入时基列表。
时基列表是跟时间相关的,处于延时的任务和等待事件有超时限制的任务都会从就绪列表中移除,然后插入时基列表。
时基列表在OSTimeTick中更新,如果任务的延时时间结束或者超时到期,就会让任务就绪,从时基列表移除,插入就绪列表。

到目前为止,我们在OS中只实现了两个列表,一个是就绪列表,一个是本章将要实现的时基列表,在本章之前,任务要么在就绪列表,要么在时基列表。

1、实现时基列表

1. 定义时基列表变量

时基列表在代码层面上由全局数组OSCfg_TickWheel[]和全局变量OSTickCtr构成,一个空的时基列表示意图见图
在这里插入图片描述

/* 时基列表大小,在os_cfg_app.h 定义 */
#define  OS_CFG_TICK_WHEEL_SIZE           17u
/* 在os_cfg_app.c 定义 */
/* 时基列表 *///(1)(2)
OS_TICK_SPOKE  OSCfg_TickWheel[OS_CFG_TICK_WHEEL_SIZE];
/* 时基列表大小 */
OS_OBJ_QTY const OSCfg_TickWheelSize = (OS_OBJ_QTY  )OS_CFG_TICK_WHEEL_SIZE;
/* 在os.h中声明 */
/* 时基列表 */
extern  OS_TICK_SPOKE  OSCfg_TickWheel[];
/* 时基列表大小 */
extern  OS_OBJ_QTY    const OSCfg_TickWheelSize;/* Tick 计数器,在os.h中定义 */
OS_EXT            OS_TICK                OSTickCtr;		//(3)
  • (1)OS_TICK_SPOKE为时基列表数组OSCfg_TickWheel[]的数据类型, 在os.h文件定义
typedefstruct  os_tick_spoke       OS_TICK_SPOKE;		
//在μC/OS-III中,内核对象的数据类型都会用大写字母重新定义。struct  os_tick_spoke {OS_TCB              *FirstPtr;		//时基列表OSCfg_TickWheel[]的每个成员都包含一条单向链表, 被插入该条链表的TCB会按照延时时间做升序排列。FirstPtr用于指向这条单向链表的第一个节点。OS_OBJ_QTY           NbrEntries;	//时基列表OSCfg_TickWheel[]的每个成员都包含一条单向链表, NbrEntries表示该条单向链表当前有多少个节点。OS_OBJ_QTY           NbrEntriesMax;	//时基列表OSCfg_TickWheel[]的每个成员都包含一条单向链表, NbrEntriesMax记录该条单向链表最多的时候有多少个节点, 在增加节点的时候会刷新,在删除节点的时候不刷新。
};
  • (2):OS_CFG_TICK_WHEEL_SIZE是一个宏, 在os_cfg_app.h中定义,用于控制时基列表的大小。
    OS_CFG_TICK_WHEEL_SIZE的推荐值为任务数/4,不推荐使用偶数,如果算出来是偶数,则加1变成质数,实际上质数是一个很好的选择。
  • (3):OSTickCtrSysTick周期计数器, 记录系统启动到现在或者从上一次复位到现在经过了多少个SysTick周期。

2. 修改任务控制块TCB

时基列表OSCfg_TickWheel[]的每个成员都包含一条单向链表,被插入该条链表的TCB会按照延时时间做升序排列,为了TCB能按照延时时间从小到大串接在一起, 需要在TCB中加入几个成员
在这里插入图片描述

struct os_tcb {CPU_STK         *StkPtr;CPU_STK_SIZE    StkSize;/* 任务延时周期个数 */OS_TICK         TaskDelayTicks;/* 任务优先级 */OS_PRIO         Prio;/* 就绪列表双向链表的下一个指针 */OS_TCB          *NextPtr;/* 就绪列表双向链表的前一个指针 */OS_TCB          *PrevPtr;/* 时基列表相关字段 */OS_TCB          *TickNextPtr;			//(1)OS_TCB          *TickPrevPtr;			//(2)OS_TICK_SPOKE   *TickSpokePtr;			//(5)OS_TICK         TickCtrMatch;			//(4)OS_TICK         TickRemain;				//(3)
};

带序号的字段可以配合上图一起理解,这样会比较容易。
上图是在时基列表 OSCfg_TickWheel[]索引11这条链表里面插入了两个TCB,一个需要延时1个时钟周期,另外一个需要延时13个时钟周期。

  • (1):TickNextPtr用于指向链表中的下一个TCB节点。
  • (2):TickPrevPtr用于指向链表中的上一个TCB节点。
  • (3):TickRemain用于设置任务还需要等待多少个时钟周期,每到来一个时钟周期,该值会递减。
  • (4):TickCtrMatch的值等于时基计数器OSTickCtr的值加上TickRemain的值, 当TickCtrMatch的值等于OSTickCtr的值的时候,表示等待到期,TCB会从链表中删除。
  • (5):每个被插入链表的TCB都包含一个字段TickSpokePtr,用于回指到链表的根部。

2、实现时基列表相关函数

时基列表相关函数在os_tick.c实现,在os.h中声明。

1. OS_TickListInit()函数

OS_TickListInit()函数用于初始化时基列表,即将全局变量OSCfg_TickWheel[]的数据域全部初始化为0

/* 初始化时基列表的数据域 */
void  OS_TickListInit (void)
{OS_TICK_SPOKE_IX   i;OS_TICK_SPOKE     *p_spoke;for (i = 0u; i < OSCfg_TickWheelSize; i++) {p_spoke                = (OS_TICK_SPOKE *)&OSCfg_TickWheel[i];p_spoke->FirstPtr      = (OS_TCB        *)0;p_spoke->NbrEntries    = (OS_OBJ_QTY     )0u;p_spoke->NbrEntriesMax = (OS_OBJ_QTY     )0u;}
}

在这里插入图片描述

2. OS_TickListInsert()函数

OS_TickListInsert()函数用于往时基列表中插入一个任务TCB
在这里插入图片描述

/* 将一个任务插入时基列表,根据延时时间的大小升序排列 */
void  OS_TickListInsert (OS_TCB *p_tcb,OS_TICK time)
{OS_TICK_SPOKE_IX   spoke;OS_TICK_SPOKE     *p_spoke;OS_TCB            *p_tcb0;OS_TCB            *p_tcb1;p_tcb->TickCtrMatch = OSTickCtr + time;			//(1)p_tcb->TickRemain   = time;			//(2)spoke   = (OS_TICK_SPOKE_IX)(p_tcb->TickCtrMatch % OSCfg_TickWheelSize);			//(3)p_spoke = &OSCfg_TickWheel[spoke];			//(4)/* 插入 OSCfg_TickWheel[spoke] 的第一个节点 */if (p_spoke->NbrEntries == (OS_OBJ_QTY)0u) 			//(5){p_tcb->TickNextPtr   = (OS_TCB   *)0;p_tcb->TickPrevPtr   = (OS_TCB   *)0;p_spoke->FirstPtr    =  p_tcb;p_spoke->NbrEntries  = (OS_OBJ_QTY)1u;}/* 如果插入的不是第一个节点,则按照TickRemain大小升序排列 */else 			//(6){/* 获取第一个节点指针 */p_tcb1 = p_spoke->FirstPtr;while (p_tcb1 != (OS_TCB *)0){/* 计算比较节点的剩余时间 */p_tcb1->TickRemain = p_tcb1->TickCtrMatch - OSTickCtr;/* 插入比较节点的后面 */if (p_tcb->TickRemain > p_tcb1->TickRemain){if (p_tcb1->TickNextPtr != (OS_TCB *)0){/* 寻找下一个比较节点 */p_tcb1 =  p_tcb1->TickNextPtr;}else{  /* 在最后一个节点插入 */p_tcb->TickNextPtr   = (OS_TCB *)0;p_tcb->TickPrevPtr   =  p_tcb1;p_tcb1->TickNextPtr  =  p_tcb;p_tcb1               = (OS_TCB *)0;			//(7)}}/* 插入比较节点的前面 */else{/* 在第一个节点插入 */if (p_tcb1->TickPrevPtr == (OS_TCB *)0) {p_tcb->TickPrevPtr   = (OS_TCB *)0;p_tcb->TickNextPtr   =  p_tcb1;p_tcb1->TickPrevPtr  =  p_tcb;p_spoke->FirstPtr    =  p_tcb;}else{/* 插入两个节点之间 */p_tcb0               =  p_tcb1->TickPrevPtr;p_tcb->TickPrevPtr   =  p_tcb0;p_tcb->TickNextPtr   =  p_tcb1;p_tcb0->TickNextPtr  =  p_tcb;p_tcb1->TickPrevPtr  =  p_tcb;}/* 跳出while循环 */p_tcb1 = (OS_TCB *)0;			//(8)}}/* 节点成功插入 */p_spoke->NbrEntries++;			//(9)}/* 刷新NbrEntriesMax的值 */if (p_spoke->NbrEntriesMax < p_spoke->NbrEntries) 			//(10){p_spoke->NbrEntriesMax = p_spoke->NbrEntries;}/* 任务TCB中的TickSpokePtr回指根节点 */p_tcb->TickSpokePtr = p_spoke;			//(11)
}
  • (1):TickCtrMatch的值等于当前时基计数器的值OSTickCtr加上任务要延时的时间timetime由函数形参传进来。
    OSTickCtr是一个全局变量, 记录的是系统自启动以来或者自上次复位以来经过了多少个SysTick周期。
    OSTickCtr的值每经过一个SysTick周期其值就加一,当TickCtrMatch的值与其相等时,就表示任务等待时间到期。
  • (2):将任务需要延时的时间time保存到TCBTickRemain, 它表示任务还需要延时多少个SysTick周期,每到来一个SysTick周期,TickRemain会减一。
  • (3):由任务的TickCtrMatch 对时基列表的大小OSCfg_TickWheelSize进行求余操作, 得出的值spoke作为时基列表OSCfg_TickWheel[]的索引。
    只要是任务的TickCtrMatchOSCfg_TickWheelSize求余后得到的值spoke相等, 那么任务的TCB就会被插入OSCfg_TickWheel[spoke]下的单向链表中,节点按照任务的TickCtrMatch值做升序排列。
    举例:在上图中,时基列表OSCfg_TickWheel[]的大小OSCfg_TickWheelSize等于12, 当前时基计数器OSTickCtr的值为10,有三个任务分别需要延时TickTemain=1TickTemain=23TickTemain=25个时钟周期, 三个任务的TickRemain加上OSTickCtr可分别得出它们的TickCtrMatch等于11、23和35, 这三个任务的TickCtrMatchOSCfg_TickWheelSize求余操作后的值spoke都等于11,所以这三个任务的TCB会被插入OSCfg_TickWheel[11]下的同一条链表, 节点顺序根据TickCtrMatch的值做升序排列。
  • (4):根据刚刚算出的索引值spoke,获取到该索引值下的成员的地址, 也叫根指针,因为该索引下对应的成员OSCfg_TickWheel[spoke]会维护一条双向的链表。
  • (5):将TCB插入链表中分两种情况,第一是当前链表是空的, 插入的节点将成为第一个节点,这个处理非常简单;第二是当前链表已经有节点。
  • (6):当前的链表中已经有节点,插入的时候则根据TickCtrMatch的值做升序排列, 插入的时候分三种情况,第一是在最后一个节点之间插入, 第二是在第一个节点插入,第三是在两个节点之间插入。
  • (7)(8):节点成功插入p_tcb1指针,跳出while循环
  • (9):节点成功插入,记录当前链表节点个数的计数器NbrEntries加一。
  • (10):刷新NbrEntriesMax的值,NbrEntriesMax用于记录当前链表曾经最多有多少个节点, 只有在增加节点的时候才刷新,在删除节点的时候是不刷新的。
  • (11):任务TCB被成功插入链表,TCB中的TickSpokePtr回指所在链表的根指针。

3. OS_TickListRemove()函数

OS_TickListRemove()用于从时基列表删除一个指定的TCB节点

/* 从时基列表中移除一个任务 */
void  OS_TickListRemove (OS_TCB  *p_tcb)
{OS_TICK_SPOKE  *p_spoke;OS_TCB         *p_tcb1;OS_TCB         *p_tcb2;/* 获取任务TCB所在链表的根指针 */p_spoke = p_tcb->TickSpokePtr;			//(1)/* 确保任务在链表中 */if (p_spoke != (OS_TICK_SPOKE *)0){/* 将剩余时间清零 */p_tcb->TickRemain = (OS_TICK)0u;/* 要移除的刚好是第一个节点 */if (p_spoke->FirstPtr == p_tcb) 			//(2){/* 更新第一个节点,原来的第一个节点需要被移除 */p_tcb1            = (OS_TCB *)p_tcb->TickNextPtr;p_spoke->FirstPtr = p_tcb1;if (p_tcb1 != (OS_TCB *)0){p_tcb1->TickPrevPtr = (OS_TCB *)0;}}/* 要移除的不是第一个节点 */			//(3)else{/* 保存要移除的节点的前后节点的指针 */p_tcb1              = p_tcb->TickPrevPtr;p_tcb2              = p_tcb->TickNextPtr;/* 节点移除,将节点前后的两个节点连接在一起 */p_tcb1->TickNextPtr = p_tcb2;if (p_tcb2 != (OS_TCB *)0){p_tcb2->TickPrevPtr = p_tcb1;}}/* 复位任务TCB中时基列表相关的字段成员 */			//(4)p_tcb->TickNextPtr  = (OS_TCB        *)0;p_tcb->TickPrevPtr  = (OS_TCB        *)0;p_tcb->TickSpokePtr = (OS_TICK_SPOKE *)0;p_tcb->TickCtrMatch = (OS_TICK        )0u;/* 节点减1 */p_spoke->NbrEntries--;			//(5)}
}
  • (1):获取任务TCB所在链表的根指针。
  • (2):要删除的节点是链表的第一个节点,这个操作很好处理,只需更新下第一个节点即可。
  • (3):要删除的节点不是链表的第一个节点,则先保存要删除的节点的前后节点,然后把这前后两个节点相连即可。
  • (4):复位任务TCB中时基列表相关的字段成员。
  • (5):节点删除成功,链表中的节点计数器NbrEntries减一。

4. OS_TickListUpdate()函数

OS_TickListUpdate()在每个SysTick周期到来时在OSTimeTick()被调用,用于更新时基计数器OSTickCtr, 扫描时基列表中的任务延时是否到期

void  OS_TickListUpdate (void)
{OS_TICK_SPOKE_IX   spoke;OS_TICK_SPOKE     *p_spoke;OS_TCB            *p_tcb;OS_TCB            *p_tcb_next;CPU_BOOLEAN        done;CPU_SR_ALLOC();/* 进入临界段 */OS_CRITICAL_ENTER();/* 时基计数器++ */OSTickCtr++;			//(1)spoke    = (OS_TICK_SPOKE_IX)(OSTickCtr % OSCfg_TickWheelSize);			//(2)p_spoke  = &OSCfg_TickWheel[spoke];p_tcb    = p_spoke->FirstPtr;done     = DEF_FALSE;while (done == DEF_FALSE){if (p_tcb != (OS_TCB *)0) 			//(3){p_tcb_next = p_tcb->TickNextPtr;p_tcb->TickRemain = p_tcb->TickCtrMatch - OSTickCtr;			//(4)/* 节点延时时间到 */if (OSTickCtr == p_tcb->TickCtrMatch) 			//(5){/* 让任务就绪 */OS_TaskRdy(p_tcb);}else 			//(6){/* 如果第一个节点延时期未满,则退出while循环因为链表是根据升序排列的,第一个节点延时期未满,那后面的肯定未满 */done = DEF_TRUE;}/* 如果第一个节点延时期满,则继续遍历链表,看看还有没有延时期满的任务如果有,则让它就绪 */p_tcb = p_tcb_next;			//(7)}else{done  = DEF_TRUE;			//(8)}}/* 退出临界段 */OS_CRITICAL_EXIT();
}
  • (1):每到来一个SysTick时钟周期,时基计数器OSTickCtr都要加一操作。
  • (2):计算要扫描的时基列表的索引,每次只扫描一条链表。
    时基列表里面有可能有多条链表,为啥只扫描其中一条链表就可以?
    因为任务在插入时基列表的时候, 插入的索引值spoke_insert是通过TickCtrMatchOSCfg_TickWheelSize求余得出。
    现在需要扫描的索引值spoke_update是通过OSTickCtrOSCfg_TickWheelSize求余得出, TickCtrMatch的值等于OSTickCtr加上TickRemain,只有在经过TickRemain个时钟周期后, spoke_update的值才有可能等于spoke_insert
    如果算出的spoke_update小于spoke_insert, 且OSCfg_TickWheel[spoke_update]下的链表的任务没有到期,那后面的肯定都没有到期,不用继续扫描。

在这里插入图片描述
举例,在上图时基列表中有三个TCB ,时基列表OSCfg_TickWheel[]的大小OSCfg_TickWheelSize等于12, 当前时基计数器OSTickCtr的值为7,有三个任务分别需要延时TickTemain=16、TickTemain=28和TickTemain=40个时钟周期, 三个任务的TickRemain加上OSTickCtr可分别得出它们的TickCtrMatch等于23、35和47
这三个任务的TickCtrMatch对OSCfg_TickWheelSize求余操作后的值spoke都等于11, 所以这三个任务的TCB会被插入OSCfg_TickWheel[11]下的同一条链表,节点顺序根据TickCtrMatch的值做升序排列。

当下一个SysTick时钟周期到来的时候,会调用OS_TickListUpdate()函数,这时OSTickCtr加一操作后等于8, 对OSCfg_TickWheelSize(等于12)求余算得要扫描更新的索引值spoke_update等8,则对OSCfg_TickWheel[8]下面的链表进行扫描, 从 图时基列表中有三个TCB 可以得知,8这个索引下没有节点,则直接退出,刚刚插入的三个TCB是在OSCfg_TickWheel[11]下的链表, 根本不用扫描,因为时间只是刚刚过了1个时钟周期而已,远远没有达到他们需要的延时时间。

  • (3):判断链表是否为空,为空则跳转到第(8)步骤。
  • (4):链表不为空,递减第一个节点的TickRemain
  • (5):判断第一个节点的延时时间是否到,如果到期,让任务就绪, 即将任务从时基列表删除,插入就绪列表,这两步由函数OS_TaskRdy()来完成, 该函数在os_core.c中定义,具体实现见 代码清单:时基列表-8。
void  OS_TaskRdy (OS_TCB  *p_tcb)
{/* 从时基列表删除 */OS_TickListRemove(p_tcb);/* 插入就绪列表 */OS_RdyListInsert(p_tcb);
}
  • (6):如果第一个节点延时期未满,则退出while循环, 因为链表是根据升序排列的,第一个节点延时期未满,那后面的肯定未满。
  • (7):如果第一个节点延时到期,则继续判断下一个节点延时是否到期。
  • (8):链表为空,退出扫描,因为其他还没到期。

3、修改OSTimeDly()函数

加入时基列表之后,OSTimeDly()函数需要被修改,迭代的代码已经用条件编译屏蔽。
在这里插入图片描述

void  OSTimeDly(OS_TICK dly)
{CPU_SR_ALLOC();/* 进入临界区 */OS_CRITICAL_ENTER();
#if 0/* 设置延时时间 */OSTCBCurPtr->TaskDelayTicks = dly;/* 从就绪列表中移除 *///OS_RdyListRemove(OSTCBCurPtr);OS_PrioRemove(OSTCBCurPtr->Prio);
#endif/* 插入时基列表 */OS_TickListInsert(OSTCBCurPtr, dly);/* 从就绪列表移除 */OS_RdyListRemove(OSTCBCurPtr);/* 退出临界区 */OS_CRITICAL_EXIT();/* 任务调度 */OSSched();
}

4、修改OSTimeTick()函数

加入时基列表之后,OSTimeTick()函数需要被修改,被迭代的代码已经用条件编译屏蔽。

void  OSTimeTick (void)
{
#if 0unsigned int i;CPU_SR_ALLOC();/* 进入临界区 */OS_CRITICAL_ENTER();for (i=0; i<OS_CFG_PRIO_MAX; i++){if (OSRdyList[i].HeadPtr->TaskDelayTicks > 0){OSRdyList[i].HeadPtr->TaskDelayTicks --;if (OSRdyList[i].HeadPtr->TaskDelayTicks == 0){/* 为0则表示延时时间到,让任务就绪 *///OS_RdyListInsert (OSRdyList[i].HeadPtr);OS_PrioInsert(i);}}}/* 退出临界区 */OS_CRITICAL_EXIT();#endif/* 更新时基列表 */OS_TickListUpdate();/* 任务调度 */OSSched();
}

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

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

相关文章

redis中List和hash数据类型

list类型是用来存储多个有序的字符串的&#xff0c;列表当中的每一个字符看做一个元素&#xff0c;一个列表当中可以存储一个或者多个元素&#xff0c;redis的list支持存储2^32-1个元素。redis可以从列表的两端进行插入&#xff08;pubsh&#xff09;和弹出&#xff08;pop&…

【安全类书籍-3】XSS跨站脚剖析与防御

目录 内容简介 作用 下载地址 内容简介 这本书涵盖以下几点: XSS攻击原理:解释XSS是如何利用Web应用未能有效过滤用户输入的缺陷,将恶意脚本注入到网页中,当其他用户访问时被执行,实现攻击者的目的,例如窃取用户会话凭证、实施钓鱼攻击等。 XSS分类:分为存储型XSS(…

【IC设计】Verilog线性序列机点灯案例(三)(小梅哥课程)

声明&#xff1a;案例和代码来自小梅哥课程&#xff0c;本人仅对知识点做做笔记&#xff0c;如有学习需要请支持官方正版。 文章目录 该系列目录设计目标设计思路RTL及Testbench代码RTL代码Testbench代码 仿真结果上板视频 该系列目录 Verilog线性序列机点灯案例(一)&#xff…

外卖点餐系统 |基于springboot框架+ Mysql+Java+JSP技术+Tomcat的外卖点餐系统 设计与实现(可运行源码+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 骑手功能模块 商家功能模块 管理员功能登录前台功能效果图 用户功能模块 系统功能设…

获取扇区航班数

1、Spark Streaming清洗服务&#xff0c;接收kafka中Topic为“task_ATC”中的数据&#xff0c;保存在MySQL中。 打开SpringBoot项目BigData-Etl-KongGuan 请认真阅读&#xff1a;在前面的“使用Spark清洗统计业务数据并保存到数据库中”任务阶段中应该已经完成了所有Topic的数…

python入门(二)

python的安装很方便&#xff0c;我们这里就不再进行讲解&#xff0c;大家可以自己去搜索视频。下面分享一下Python的入门知识点。 执行命令的方式 在安装好python后&#xff0c;有两种方式可以执行命令&#xff1a; 命令行程序文件&#xff0c;后缀名为.py 对于命令行&…

Github 2024-03-16 开源项目日报Top10

根据Github Trendings的统计,今日(2024-03-16统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目5非开发语言项目2TypeScript项目1C++项目1Lua项目1Swift项目1《Hello 算法》:动画图解、一键运行的数据结构与算法教程 创建周期:4…

Linux服务器(Debian系)包含UOS安全相关巡检shell脚本

#!/bin/bash# Define output file current_date$(date "%Y%m%d") # Gets the current date in YYYYMMDD format output_file"server_security_inspection_report_${current_date}.txt"# Empty the file initially echo > $output_file# 获取巡检时间 (…

暴雨高性能分布式存储为AI提供坚实数据存力

随着两会的圆满落幕&#xff0c;新质生产力和人工智能的发展成为社会各界热议的焦点。总理在两会后的首次调研中&#xff0c;特别强调了新质生产力和人工智能的重要性&#xff0c;这无疑为人工智能产业的蓬勃发展注入了新的动力。 年初&#xff0c;Sora所引领的人工智能热潮更…

【分布式websocket 】前端vuex管理客户端消息crud!使用localStorage来存储【第19期】

前言 聊天系统客户端是要存储消息的&#xff0c;因为所有所有的历史消息都从服务器拉的话一方面服务器压力大&#xff0c;另一方面也耗费用户流量。所以客户端存储消息是势在必行的。如何存储呢上一篇文章也写了&#xff0c;大概就是浏览器的话是localStorage或者IndexedDB。然…

MIT线性代数-方程组的几何解释

文章目录 1. 二维空间1.1 行方向1.2 列方向 2. 三维空间2.1 行方向2.2 列方向 假设有一个方程组 A X B AXB AXB表示如下 2 x − y 0 (1) 2x-y0\tag{1} 2x−y0(1) − x 2 y 3 (2) -x2y3\tag{2} −x2y3(2) 矩阵表示如下&#xff1a; [ 2 − 1 − 1 2 ] [ x y ] [ 0 3 ] (3)…

(四)Android布局类型(线性布局LinearLayout)

线性布局&#xff08;LinearLayout&#xff09;&#xff1a;按照一定的方向排列组件&#xff0c;方向主要分为水平方向和垂直方向。方向的设置通过属性android:orientation设置 android:orientation 其取值有两种 水平方向&#xff1a;android:orientation"horizontal&…

Java中如何解决if-else(策略+枚举)

最近接到了一个新需求&#xff0c;按照不同的编码去执行不同的逻辑&#xff0c;但最后返回的数据类型是一致的&#xff0c;都是相同对象的List集合。 完成这个需求的话可以使用if-else来执行不同的方法&#xff0c;虽然if-else可以实现&#xff0c;但if-else是一种面向过程的实…

MongoDB——linux中yum命令安装及配置

一、创建mongodb-org-3.4.repo文件 vi /etc/yum.repos.d/mongodb-org-3.4.repo 将下面内容添加到创建的文件中 [mongodb-org-3.4] nameMongoDB Repository baseurlhttps://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.4/x86_64/ gpgcheck1 enabled1 gpgkeyhttps://www…

本地用AIGC生成图像与视频

最近AI界最火的话题&#xff0c;当属Sora了。遗憾的是&#xff0c;Sora目前还没开源或提供模型下载&#xff0c;所以没法在本地跑起来。但是&#xff0c;业界有一些开源的图像与视频生成模型。虽然效果上还没那么惊艳&#xff0c;但还是值得我们体验与学习下的。 Stable Diffu…

Ubuntu Linux - Primavera P6 EPPM 安装及分享

引言 根据计划&#xff0c;近日我制作了基于Ubuntu Linux 的P6虚拟机环境&#xff0c;同样里面包含了全套P6 最新版应用服务 此虚拟机仅用于演示、培训和测试目的。如您在生产环境中使用此虚拟机&#xff0c;请先与Oracle Primavera销售代表取得联系&#xff0c;以获取所需的应…

无人机助力智慧农田除草新模式,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建无人机航拍场景下的农田杂草检测识别系统

科技发展到今天&#xff0c;无人机喷洒药物已经不是一件新鲜事情了&#xff0c;在很多高危的工作领域中&#xff0c;比如高空电力设备除冰&#xff0c;电力设备部件传送更换等等&#xff0c;无人机都可以扮演非常出色的作用&#xff0c;前面回到老家一段时间&#xff0c;最近正…

吴恩达deeplearning.ai:使用多个决策树随机森林

以下内容有任何不理解可以翻看我之前的博客哦&#xff1a;吴恩达deeplearning.ai专栏 文章目录 为什么要使用树集合使用多个决策树(Tree Ensemble)有放回抽样随机森林XGBoost(eXtream Gradient Boosting)XGBoost的库实现何时使用决策树决策树和树集合神经网络 使用单个决策树的…

【开源】SpringBoot框架开发房屋出售出租系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 房屋销售模块2.2 房屋出租模块2.3 预定意向模块2.4 交易订单模块 三、系统展示四、核心代码4.1 查询房屋求租单4.2 查询卖家的房屋求购单4.3 出租意向预定4.4 出租单支付4.5 查询买家房屋销售交易单 五、免责说明 一、摘…

短视频矩阵系统/短视频矩阵系统技术saas研发

短视频矩阵系统SaaS研发是一个复杂且需要技术专业知识的工作。以下是一些关键步骤和建议&#xff0c;帮助你开发一个成功的短视频矩阵系统SaaS&#xff1a; 1. 明确需求&#xff1a;首先&#xff0c;你需要明确你的短视频矩阵系统的具体需求&#xff0c;例如用户规模、视频内容…