当前位置: 首页 > news >正文

鸿蒙内核源码分析(中断管理篇) | 江湖从此不再怕中断

关于中断部分系列篇将用三篇详细说明整个过程.

  • 中断概念篇 中断概念很多,比如中断控制器,中断源,中断向量,中断共享,中断处理程序等等.本篇做一次整理.先了解透概念才好理解中断过程.用海公公打比方说明白中断各个概念.可前往查看.

  • 中断管理篇(本篇) 从中断初始化HalIrqInit开始,到注册中断的LOS_HwiCreate函数,到消费中断函数的 HalIrqHandler,剖析鸿蒙内核实现中断的过程,很像设计模式中的观察者模式.

  • 中断切换篇 用自下而上的方式,从中断源头纯汇编代码往上跟踪代码细节.说清楚保存和恢复中断现场TaskIrqContext过程.

编译开关

//....
#define LOSCFG_ARCH_ARM_VER "armv7-a"
#define LOSCFG_ARCH_CPU "cortex-a7"
#define LOSCFG_PLATFORM "hi3516dv300"
#define LOSCFG_PLATFORM_BSP_GIC_V2 1
#define LOSCFG_PLATFORM_ROOTFS 1
#define LOSCFG_KERNEL_CPPSUPPORT 1
#define LOSCFG_HW_RANDOM_ENABLE 1
#define LOSCFG_ARCH_CORTEX_A7 1
#define LOSCFG_DRIVERS_HDF_PLATFORM_RTC 1
#define LOSCFG_DRIVERS_HDF_PLATFORM_UART 1

中断初始化

hi3516dv300 中断控制器选择了 LOSCFG_PLATFORM_BSP_GIC_V2 ,对应代码为 gic_v2.c
GIC(Generic Interrupt Controller)是ARM公司提供的一个通用的中断控制器.
看这种代码因为涉及硬件部分,需要对照 ARM中断控制器 gic_v2.pdf 文档看.可前往地址下载查看.

//硬件中断初始化
VOID HalIrqInit(VOID)
{UINT32 i;/* set externel interrupts to be level triggered, active low. */	//将外部中断设置为电平触发,低电平激活for (i = 32; i < OS_HWI_MAX_NUM; i += 16) {GIC_REG_32(GICD_ICFGR(i / 16)) = 0;}/* set externel interrupts to CPU 0 */	//将外部中断设置为CPU 0for (i = 32; i < OS_HWI_MAX_NUM; i += 4) {GIC_REG_32(GICD_ITARGETSR(i / 4)) = 0x01010101;}/* set priority on all interrupts */	//设置所有中断的优先级for (i = 0; i < OS_HWI_MAX_NUM; i += 4) {GIC_REG_32(GICD_IPRIORITYR(i / 4)) = GICD_INT_DEF_PRI_X4;}/* disable all interrupts. */			//禁用所有中断。for (i = 0; i < OS_HWI_MAX_NUM; i += 32) {GIC_REG_32(GICD_ICENABLER(i / 32)) = ~0;}HalIrqInitPercpu();//初始化当前CPU中断信息/* enable gic distributor control */GIC_REG_32(GICD_CTLR) = 1; //使能分发中断寄存器,该寄存器作用是允许给CPU发送中断信号#if (LOSCFG_KERNEL_SMP == YES)/* register inter-processor interrupt *///注册核间中断,啥意思?就是CPU各核直接可以发送中断信号//处理器间中断允许一个CPU向系统其他的CPU发送中断信号,处理器间中断(IPI)不是通过IRQ线传输的,而是作为信号直接放在连接所有CPU本地APIC的总线上。LOS_HwiCreate(LOS_MP_IPI_WAKEUP, 0xa0, 0, OsMpWakeHandler, 0);//注册唤醒CPU的中断处理函数LOS_HwiCreate(LOS_MP_IPI_SCHEDULE, 0xa0, 0, OsMpScheduleHandler, 0);//注册调度CPU的中断处理函数LOS_HwiCreate(LOS_MP_IPI_HALT, 0xa0, 0, OsMpScheduleHandler, 0);//注册停止CPU的中断处理函数
#endif
}
//给每个CPU core初始化硬件中断
VOID HalIrqInitPercpu(VOID)
{/* unmask interrupts */	//取消中断屏蔽GIC_REG_32(GICC_PMR) = 0xFF;/* enable gic cpu interface */	//启用gic cpu接口GIC_REG_32(GICC_CTLR) = 1;
}

解读

  • 上来四个循环,是对中断控制器寄存器组的初始化,也就是驱动程序,驱动程序是配置硬件寄存器的过程.寄存器分通用和专用寄存器.下图为 gic_v2 的寄存器功能 ,这里对照代码和datasheet重点说下中断配置寄存器(GICD_ICFGRn)

  • 以下是GICD_ICFGRn的介绍

    The GICD_ICFGRs provide a 2-bit Int_config field for each interrupt supported by the GIC.
    This field identifies whether the corresponding interrupt is edge-triggered or level-sensitive

    GICD_ICFGRs为GIC支持的每个中断提供一个2位配置字段。此字段标识相应的中断是边缘触发的还是电平触发的

    0xC00 - 0xCFC GICD_ICFGRn RW IMPLEMENTATION DEFINED Interrupt Configuration Registers#define GICD_ICFGR(n)                   (GICD_OFFSET + 0xc00 + (n) * 4) /* Interrupt Configuration Registers */		//中断配置寄存器

如此一个32位寄存器可以记录16个中断的信息,这也是代码中出现 GIC_REG_32(GICD_ICFGR(i / 16))的原因.

  • GIC-v2支持三种类型的中断

    • PPI:私有外设中断(Private Peripheral Interrupt),是每个CPU私有的中断。最多支持16个PPI中断,硬件中断号从ID16~ID31。PPI通常会送达到指定的CPU上,应用场景有CPU本地时钟。
    • SPI:公用外设中断(Shared Peripheral Interrupt),最多可以支持988个外设中断,硬件中断号从ID32~ID1019。
    • SGI:软件触发中断(Software Generated Interrupt)通常用于多核间通讯,最多支持16个SGI中断,硬件中断号从ID0~ID15。SGI通常在内核中被用作 IPI 中断(inter-processor interrupts),并会送达到系统指定的CPU上,函数的最后就注册了三个核间中断的函数.
        typedef enum {//核间中断LOS_MP_IPI_WAKEUP,	//唤醒CPULOS_MP_IPI_SCHEDULE,//调度CPULOS_MP_IPI_HALT,	//停止CPU} MP_IPI_TYPE;

中断相关的结构体

size_t g_intCount[LOSCFG_KERNEL_CORE_NUM] = {0};//记录每个CPUcore的中断数量 
HwiHandleForm g_hwiForm[OS_HWI_MAX_NUM];//中断注册表 @note_why 用 form 来表示?有种写 HTML的感觉 :P
STATIC CHAR *g_hwiFormName[OS_HWI_MAX_NUM] = {0};//记录每个硬中断的名称 
STATIC UINT32 g_hwiFormCnt[OS_HWI_MAX_NUM] = {0};//记录每个硬中断的总数量
STATIC UINT32 g_curIrqNum = 0; //记录当前中断号
typedef VOID (*HWI_PROC_FUNC)(VOID); //中断函数指针
typedef struct tagHwiHandleForm {	HWI_PROC_FUNC pfnHook;	//中断处理函数HWI_ARG_T uwParam;		//中断处理函数参数struct tagHwiHandleForm *pstNext;	//节点,指向下一个中断,用于共享中断的情况
} HwiHandleForm;typedef struct tagIrqParam {	//中断参数int swIrq;		//	软件中断VOID *pDevId;	//	设备IDconst CHAR *pName;	//名称
} HwiIrqParam;

注册硬中断

/******************************************************************************创建一个硬中断中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,handleIrq会调用该中断处理程序
******************************************************************************/
LITE_OS_SEC_TEXT_INIT UINT32 LOS_HwiCreate(HWI_HANDLE_T hwiNum,	//硬中断句柄编号 默认范围[0-127]HWI_PRIOR_T hwiPrio,		//硬中断优先级	HWI_MODE_T hwiMode,		//硬中断模式 共享和非共享HWI_PROC_FUNC hwiHandler,//硬中断处理函数HwiIrqParam *irqParam)	//硬中断处理函数参数
{UINT32 ret;(VOID)hwiPrio;if (hwiHandler == NULL) {//中断处理函数不能为NULLreturn OS_ERRNO_HWI_PROC_FUNC_NULL;}if ((hwiNum > OS_USER_HWI_MAX) || ((INT32)hwiNum < OS_USER_HWI_MIN)) {//中断数区间限制 [32,96]return OS_ERRNO_HWI_NUM_INVALID;}#ifdef LOSCFG_NO_SHARED_IRQ	//不支持共享中断ret = OsHwiCreateNoShared(hwiNum, hwiMode, hwiHandler, irqParam);
#elseret = OsHwiCreateShared(hwiNum, hwiMode, hwiHandler, irqParam);
#endifreturn ret;
}
//创建一个共享硬件中断,共享中断就是一个中断能触发多个响应函数
STATIC UINT32 OsHwiCreateShared(HWI_HANDLE_T hwiNum, HWI_MODE_T hwiMode,HWI_PROC_FUNC hwiHandler, const HwiIrqParam *irqParam)
{UINT32 intSave;HwiHandleForm *hwiFormNode = NULL;HwiHandleForm *hwiForm = NULL;HwiIrqParam *hwiParam = NULL;HWI_MODE_T modeResult = hwiMode & IRQF_SHARED;if (modeResult && ((irqParam == NULL) || (irqParam->pDevId == NULL))) {return OS_ERRNO_HWI_SHARED_ERROR;}HWI_LOCK(intSave);//中断自旋锁hwiForm = &g_hwiForm[hwiNum];//获取中断处理项if ((hwiForm->pstNext != NULL) && ((modeResult == 0) || (!(hwiForm->uwParam & IRQF_SHARED)))) {HWI_UNLOCK(intSave);return OS_ERRNO_HWI_SHARED_ERROR;}while (hwiForm->pstNext != NULL) {//pstNext指向 共享中断的各处理函数节点,此处一直撸到最后一个hwiForm = hwiForm->pstNext;//找下一个中断hwiParam = (HwiIrqParam *)(hwiForm->uwParam);//获取中断参数,用于检测该设备ID是否已经有中断处理函数if (hwiParam->pDevId == irqParam->pDevId) {//设备ID一致时,说明设备对应的中断处理函数已经存在了.HWI_UNLOCK(intSave);return OS_ERRNO_HWI_ALREADY_CREATED;}}hwiFormNode = (HwiHandleForm *)LOS_MemAlloc(m_aucSysMem0, sizeof(HwiHandleForm));//创建一个中断处理节点if (hwiFormNode == NULL) {HWI_UNLOCK(intSave);return OS_ERRNO_HWI_NO_MEMORY;}hwiFormNode->uwParam = OsHwiCpIrqParam(irqParam);//获取中断处理函数的参数if (hwiFormNode->uwParam == LOS_NOK) {HWI_UNLOCK(intSave);(VOID)LOS_MemFree(m_aucSysMem0, hwiFormNode);return OS_ERRNO_HWI_NO_MEMORY;}hwiFormNode->pfnHook = hwiHandler;//绑定中断处理函数hwiFormNode->pstNext = (struct tagHwiHandleForm *)NULL;//指定下一个中断为NULL,用于后续遍历找到最后一个中断项(见于以上 while (hwiForm->pstNext != NULL)处)hwiForm->pstNext = hwiFormNode;//共享中断if ((irqParam != NULL) && (irqParam->pName != NULL)) {g_hwiFormName[hwiNum] = (CHAR *)irqParam->pName;}g_hwiForm[hwiNum].uwParam = modeResult;HWI_UNLOCK(intSave);return LOS_OK;
}

解读

  • 内核将硬中断进行编号,如:
      #define NUM_HAL_INTERRUPT_TIMER0        33#define NUM_HAL_INTERRUPT_TIMER1        33#define NUM_HAL_INTERRUPT_TIMER2        34#define NUM_HAL_INTERRUPT_TIMER3        34#define NUM_HAL_INTERRUPT_TIMER4        35#define NUM_HAL_INTERRUPT_TIMER5        35#define NUM_HAL_INTERRUPT_TIMER6        36#define NUM_HAL_INTERRUPT_TIMER7        36#define NUM_HAL_INTERRUPT_DMAC          60#define NUM_HAL_INTERRUPT_UART0         38#define NUM_HAL_INTERRUPT_UART1         39#define NUM_HAL_INTERRUPT_UART2         40#define NUM_HAL_INTERRUPT_UART3         41#define NUM_HAL_INTERRUPT_UART4         42#define NUM_HAL_INTERRUPT_TIMER         NUM_HAL_INTERRUPT_TIMER4

例如:时钟节拍处理函数 OsTickHandler 就是在 HalClockInit中注册的

    //硬时钟初始化VOID HalClockInit(VOID){// ...(void)LOS_HwiCreate(NUM_HAL_INTERRUPT_TIMER, 0xa0, 0, OsTickHandler, 0);//注册OsTickHandler到中断向量表 }//节拍中断处理函数 ,鸿蒙默认10ms触发一次LITE_OS_SEC_TEXT VOID OsTickHandler(VOID){UINT32 intSave;TICK_LOCK(intSave);//tick自旋锁g_tickCount[ArchCurrCpuid()]++;// 累加当前CPU核tick数TICK_UNLOCK(intSave);OsTimesliceCheck();//时间片检查OsTaskScan(); /* task timeout scan *///扫描超时任务 例如:delay(300)#if (LOSCFG_BASE_CORE_SWTMR == YES)OsSwtmrScan();//扫描定时器,查看是否有超时定时器,加入队列#endif} 
  • 鸿蒙是支持中断共享的,在OsHwiCreateShared中,将函数注册到g_hwiForm中.中断向量完成注册后,就是如何触发和回调的问题.触发在中断切换篇中已经讲清楚,触发是从底层汇编向上调用,调用的C函数就是HalIrqHandler

中断怎么触发的?

分两种情况:

  • 通过硬件触发,比如按键,USB的插拔这些中断源向中断控制器发送电信号(高低电平触发或是上升/下降沿触发),中断控制器经过过滤后将信号发给对应的CPU处理,通过硬件改变PC和CPSR寄存值,直接跳转到中断向量(固定地址)执行.
      b   reset_vector            @开机代码b   _osExceptUndefInstrHdl 	@异常处理之CPU碰到不认识的指令b   _osExceptSwiHdl			@异常处理之:软中断b   _osExceptPrefetchAbortHdl	@异常处理之:取指异常b   _osExceptDataAbortHdl		@异常处理之:数据异常b   _osExceptAddrAbortHdl		@异常处理之:地址异常b   OsIrqHandler				@异常处理之:硬中断b   _osExceptFiqHdl				@异常处理之:快中断
  • 通过软件触发,常见于核间中断的情况, 核间中断指的是几个CPU之间相互通讯的过程.以下为某一个CPU向其他CPU(可以是多个)发起让这些CPU重新调度LOS_MpSchedule的中断请求信号.最终是写了中断控制器的GICD_SGIR寄存器,这是一个由软件触发中断的寄存器.中断控制器会将请求分发给对应的CPU处理中断,即触发了OsIrqHandler.
    //给参数CPU发送调度信号VOID LOS_MpSchedule(UINT32 target)//target每位对应CPU core {UINT32 cpuid = ArchCurrCpuid();target &= ~(1U << cpuid);//获取除了自身之外的其他CPUHalIrqSendIpi(target, LOS_MP_IPI_SCHEDULE);//向目标CPU发送调度信号,核间中断(Inter-Processor Interrupts),IPI}//SGI软件触发中断(Software Generated Interrupt)通常用于多核间通讯STATIC VOID GicWriteSgi(UINT32 vector, UINT32 cpuMask, UINT32 filter){UINT32 val = ((filter & 0x3) << 24) | ((cpuMask & 0xFF) << 16) |(vector & 0xF);GIC_REG_32(GICD_SGIR) = val;//写SGI寄存器}//向指定核发送核间中断VOID HalIrqSendIpi(UINT32 target, UINT32 ipi){GicWriteSgi(ipi, target, 0);}

中断统一处理入口函数 HalIrqHandler

//硬中断统一处理函数,这里由硬件触发,调用见于 ..\arch\arm\arm\src\los_dispatch.S
VOID HalIrqHandler(VOID)
{UINT32 iar = GIC_REG_32(GICC_IAR);//从中断确认寄存器获取中断ID号UINT32 vector = iar & 0x3FFU;//计算中断向量号/** invalid irq number, mainly the spurious interrupts 0x3ff,* gicv2 valid irq ranges from 0~1019, we use OS_HWI_MAX_NUM* to do the checking.*/if (vector >= OS_HWI_MAX_NUM) {return;}g_curIrqNum = vector;//记录当前中断ID号OsInterrupt(vector);//调用上层中断处理函数/* use orignal iar to do the EOI */GIC_REG_32(GICC_EOIR) = iar;//更新中断结束寄存器
}
VOID OsInterrupt(UINT32 intNum)//中断实际处理函数
{HwiHandleForm *hwiForm = NULL;UINT32 *intCnt = NULL;intCnt = &g_intCount[ArchCurrCpuid()];//当前CPU的中断总数量 ++*intCnt = *intCnt + 1;//@note_why 这里没看明白为什么要 +1#ifdef LOSCFG_CPUP_INCLUDE_IRQ //开启查询系统CPU的占用率的中断OsCpupIrqStart();//记录本次中断处理开始时间
#endif#ifdef LOSCFG_KERNEL_TICKLESSOsTicklessUpdate(intNum);
#endifhwiForm = (&g_hwiForm[intNum]);//获取对应中断的实体
#ifndef LOSCFG_NO_SHARED_IRQ	//如果没有定义不共享中断 ,意思就是如果是共享中断while (hwiForm->pstNext != NULL) { //一直撸到最后hwiForm = hwiForm->pstNext;//下一个继续撸
#endifif (hwiForm->uwParam) {//有参数的情况HWI_PROC_FUNC2 func = (HWI_PROC_FUNC2)hwiForm->pfnHook;//获取回调函数if (func != NULL) {UINTPTR *param = (UINTPTR *)(hwiForm->uwParam);func((INT32)(*param), (VOID *)(*(param + 1)));//运行带参数的回调函数}} else {//木有参数的情况HWI_PROC_FUNC0 func = (HWI_PROC_FUNC0)hwiForm->pfnHook;//获取回调函数if (func != NULL) {func();//运行回调函数}}
#ifndef LOSCFG_NO_SHARED_IRQ}
#endif++g_hwiFormCnt[intNum];//中断号计数器总数累加*intCnt = *intCnt - 1;	//@note_why 这里没看明白为什么要 -1 
#ifdef LOSCFG_CPUP_INCLUDE_IRQ	//开启查询系统CPU的占用率的中断OsCpupIrqEnd(intNum);//记录中断处理时间完成时间
#endif
}

解读
统一中断处理函数是一个通过一个中断号去找到注册函数的过程,分四步走:

  • 第一步:取号,这号是由中断控制器的 GICC_IAR寄存器提供的,这是一个专门保存当前中断号的寄存器.
  • 第二步:从注册表g_hwiForm中查询注册函数,同时取出参数.
  • 第三步:执行函数,也就是回调注册函数,分有参和无参两种情况 func(...),在中断共享的情况,注册函数会指向 next 注册函数pstNext,依次执行回调函数,这是中断共享的实现细节.
    typedef struct tagHwiHandleForm {	HWI_PROC_FUNC pfnHook;	//中断处理函数HWI_ARG_T uwParam;		//中断处理函数参数struct tagHwiHandleForm *pstNext;	//节点,指向next中断,用于共享中断的情况} HwiHandleForm;
  • 第四步:销号,本次中断完成了就需要消除记录,中断控制器也有专门的销号寄存器GICC_EOIR
  • 另外的是一些统一数据,每次中断号处理内核都会记录次数,和耗时,以便定位/跟踪/诊断问题.

鸿蒙全栈开发全新学习指南

也为了积极培养鸿蒙生态人才,让大家都能学习到鸿蒙开发最新的技术,针对一些在职人员、0基础小白、应届生/计算机专业、鸿蒙爱好者等人群,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线【包含了大厂APP实战项目开发】

本路线共分为四个阶段:

第一阶段:鸿蒙初中级开发必备技能

第二阶段:鸿蒙南北双向高工技能基础:gitee.com/MNxiaona/733GH

第三阶段:应用开发中高级就业技术

第四阶段:全网首发-工业级南向设备开发就业技术:https://gitee.com/MNxiaona/733GH

《鸿蒙 (Harmony OS)开发学习手册》(共计892页)

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

开发基础知识:gitee.com/MNxiaona/733GH

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

基于ArkTS 开发

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

鸿蒙开发面试真题(含参考答案):gitee.com/MNxiaona/733GH

鸿蒙入门教学视频:

美团APP实战开发教学:gitee.com/MNxiaona/733GH

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:gitee.com/MNxiaona/733GH

相关文章:

鸿蒙内核源码分析(中断管理篇) | 江湖从此不再怕中断

关于中断部分系列篇将用三篇详细说明整个过程. 中断概念篇 中断概念很多&#xff0c;比如中断控制器&#xff0c;中断源&#xff0c;中断向量&#xff0c;中断共享&#xff0c;中断处理程序等等.本篇做一次整理.先了解透概念才好理解中断过程.用海公公打比方说明白中断各个概念…...

php使用rabbitmq

这里使用的是 php-amqplib composer require php-amqplib/php-amqplib生产端send.php <?phprequire_once "./vendor/autoload.php";use PhpAmqpLib\Connection\AMQPStreamConnection; use PhpAmqpLib\Message\AMQPMessage;//交换机名称 $exc_name exchange.can…...

前端发起网络请求的几种常见方式(XMLHttpRequest、FetchApi、jQueryAjax、Axios)

摘要 前端发起网络请求的几种常见方式包括&#xff1a; XMLHttpRequest (XHR)&#xff1a; 这是最传统和最常见的方式之一。它允许客户端与服务器进行异步通信。XHR API 提供了一个在后台发送 HTTP 请求和接收响应的机制&#xff0c;使得页面能够在不刷新的情况下更新部分内容…...

通过氧气退火增强β-Ga₂O₃二极管.中国科技大学和河北半导体研究所的研究人员在这一特定领域取得了最新重大进展

上图所示&#xff1a;&#xff08;a&#xff09;增加台面有助于提高β-Ga2O3肖特基势垒二极管的阻断电压&#xff08;b&#xff09;。 氧气退火和自对准台面终端使β-Ga2O3二极管进一步走向商业化。 虽然β-Ga2O3电力电子技术已经取得了长足的进步&#xff0c;但仍然存在挑战&…...

C语言猜数字游戏

用C语言实现猜数字游戏&#xff0c;电脑随机给出一个范围内的数字&#xff0c;用户在终端输入数字&#xff0c;去猜大小&#xff1b;对比数字&#xff0c;电脑给出提示偏大还是偏小&#xff1b;不断循环&#xff0c;直到正确 #include <stdio.h> #include <time.h>…...

笔记本连接不上远程桌面,笔记本无法连接远程桌面的可能原因及解决方法

在使用远程桌面功能时&#xff0c;笔记本无法成功连接的情况可能由多种原因引起。为了有效地解决这个问题&#xff0c;我们需要逐一排查这些可能的原因&#xff0c;并采取相应的解决措施。 首先&#xff0c;网络连接稳定性是远程桌面连接成功的关键。请确保笔记本和远程计算机之…...

Android 音视频播放器 Demo(一)—— 视频解码与渲染

本篇作为 Android 音视频实战系列的第二篇文章&#xff0c;主要介绍视频解码与渲染过程。本系列文章目录如下&#xff1a; Android 音视频基础知识 Android 音视频播放器 Demo&#xff08;一&#xff09;—— 视频解码与渲染 Android 音视频播放器 Demo&#xff08;二&#xff…...

Flutter笔记:Widgets Easier组件库(3)使用按钮组件

Flutter笔记 Widgets Easier组件库&#xff08;3&#xff09;&#xff1a;使用按钮组件 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddre…...

荷香堪筑梦,鸳鸯和月寻。(变相BFS搜索)

本题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目&#xff1a; 样例&#xff1a; 输入 3 4 2 .... ***. ..a. 输出 yes 思路&#xff1a; 根据题意&#xff0c;这里 1 s 可以移动多次&#xff0c;我们将每次可以移动避开雪的的位置存储起来&#xff0c;判断当…...

智慧公厕建设,打造智慧城市基础设施新亮点

公共厕所是城市基础设施的重要组成部分&#xff0c;而智慧公厕的建设则是现代城市管理的创新之举。为了实现公厕的精细化管理和提供更便捷的服务&#xff0c;推进智慧公厕建设必须要实现技术融合、业务融合、数据融合的目标&#xff0c;跨越层级、地域、系统、部门和业务的限制…...

Kubernetes 教程:在 Containerd 容器中使用 GPU

原文链接:Kubernetes 教程:在 Containerd 容器中使用 GPU 云原生实验室本文介绍了如何在使用 Containerd 作为运行时的 Kubernetes 集群中使用 GPU 资源。https://fuckcloudnative.io/posts/add-nvidia-gpu-support-to-k8s-with-containerd/ 前两天闹得沸沸扬扬的事件不知道…...

LNMP部署wordpress

1.环境准备 总体架构介绍 序号类型名称外网地址内网地址软件02负载均衡服务器lb0110.0.0.5192.168.88.5nginx keepalived03负载均衡服务器lb0210.0.0.6192.168.88.6nginx keepalived04web服务器web0110.0.0.7192.168.88.7nginx05web服务器web0210.0.0.8192.168.88.8nginx06we…...

本地部署大模型ollama+docker+open WebUI/Lobe Chat

文章目录 大模型工具Ollama下载安装运行Spring Ai 代码测试加依赖配置写代码 ollama的web&Desktop搭建部署Open WebUI有两种方式Docker DesktopDocker部署Open WebUIDocker部署Lobe Chat可以配置OpenAI的key也可以配置ollama 大模型的选择 本篇基于windows环境下配置 大模型…...

qt学习篇---界面按键关联(信号和槽)

目录 1.qt基础 2.做一个界面 创建project UI界面设计 信号和槽 1.控件改名字 2.什么是信号和槽 3.怎么关联信号和槽 自动关联 手动关联 1.qt基础 qt可移植性强&#xff0c;不久会用到MCU。很有意义学习 2.做一个界面 创建project 不要中文路径 选择QWidget .pro文件…...

python Django 的内置权限系统或自定义模型来存储更复杂的角色和权限关系

在 Django 中,管理用户权限和角色通常涉及到使用 Django 的内置权限系统或自定义模型来存储更复杂的角色和权限关系。下面是一个基本的指南,说明如何在 Django 中为后台管理系统分配权限并将其保存在数据库中,同时结合 Vue.js 和 Element UI 作为前端框架。 后端(Django)…...

不上班,我靠这5份赚钱副业养活了自己

在这个快节奏的社会里&#xff0c;很多人都在为生活奔波忙碌。今天&#xff0c;就让我来跟大家分享一下我的“躺平”秘籍吧&#xff01; 这一个月来&#xff0c;我没有上班&#xff0c;但好在有副业养活自己。有时候&#xff0c;我真的觉得有一份自己喜欢的自媒体副业挺好的。…...

强一致性的皇冠:分布式事务模型的至高法则揭秘

关注微信公众号 “程序员小胖” 每日技术干货&#xff0c;第一时间送达&#xff01; 引言 分布式事务模型是分布式系统设计的核心&#xff0c;关键在于保证数据一致性和事务完整性&#xff0c;尤其强调强一致性。诸如2PC、3PC、Saga、TCC等模型与协议&#xff0c;应运而生以解…...

mac/windows下安装docker,minikube

1、安装docker Get Started | Docker 下载安装docker 就行 启动后&#xff0c;就可以正常操作docker了 使用docker -v 验证是否成功就行 2、安装minikube&#xff0c;是基于docker-desktop的 2.1、点击设置 2.2、选中安装&#xff0c;这个可能需要一点时间 这样安装后&…...

【爬虫】fake_useragent的使用、BeautifulSoup(find()和find_all())

1 fake_useragent 2 BeautifulSoup 3 Beautiful Soup库的find()和find_all() 1 fake_useragent fake_useragent是一个Python库&#xff0c;用于生成随机的用户代理字符串。 用户代理是在HTTP请求中发送给服务器的一种标识&#xff0c;它告诉服务器发送请求的客户端的类型、版本…...

ComfyUI中图像亮度/对比度/饱和度处理

用上面这个节点可以同时设置图片的亮度、对比度和饱和度。 【保姆级教程】一口气分享在ComfyUI中常用的30多种基本图像处理方式 更多好玩且实用AIGC工作流和节点 星球号&#xff1a;32767063 本期资料链接 往期学习资料 整理AI学习资料库...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

论文阅读:Matting by Generation

今天介绍一篇关于 matting 抠图的文章&#xff0c;抠图也算是计算机视觉里面非常经典的一个任务了。从早期的经典算法到如今的深度学习算法&#xff0c;已经有很多的工作和这个任务相关。这两年 diffusion 模型很火&#xff0c;大家又开始用 diffusion 模型做各种 CV 任务了&am…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...