鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源?

官方基本概念

  • 从系统的角度看,进程是资源管理单元。进程可以使用或等待CPU、使用内存空间等系统资源,并独立于其它进程运行。

  • OpenHarmony内核的进程模块可以给用户提供多个进程,实现了进程之间的切换和通信,帮助用户管理业务程序流程。这样用户可以将更多的精力投入到业务功能的实现中。

  • OpenHarmony内核中的进程采用抢占式调度机制,支持时间片轮转调度方式和FIFO调度机制。

  • OpenHarmony内核的进程一共有32个优先级(0-31),用户进程可配置的优先级有22个(10-31),最高优先级为10,最低优先级为31。

  • 高优先级的进程可抢占低优先级进程,低优先级进程必须在高优先级进程阻塞或结束后才能得到调度。

  • 每一个用户态进程均拥有自己独立的进程空间,相互之间不可见,实现进程间隔离。

  • 用户态根进程init由内核态创建,其它用户态进程均由init进程fork而来。

进程状态说明:

  • 初始化(Init):该进程正在被创建。

  • 就绪(Ready):该进程在就绪列表中,等待CPU调度。

  • 运行(Running):该进程正在运行。

  • 阻塞(Pend):该进程被阻塞挂起。本进程内所有的线程均被阻塞时,进程被阻塞挂起。

  • 僵尸态(Zombies):该进程运行结束,等待父进程回收其控制块资源。

鸿蒙task

  • Init→Ready:

    进程创建或fork时,拿到该进程控制块后进入Init状态,处于进程初始化阶段,当进程初始化完成将进程插入调度队列,此时进程进入就绪状态。

  • Ready→Running:

    进程创建后进入就绪态,发生进程切换时,就绪列表中最高优先级的进程被执行,从而进入运行态。若此时该进程中已无其它线程处于就绪态,则该进程从就绪列表删除,只处于运行态;若此时该进程中还有其它线程处于就绪态,则该进程依旧在就绪队列,此时进程的就绪态和运行态共存。

  • Running→Pend:

    进程内所有的线程均处于阻塞态时,进程在最后一个线程转为阻塞态时,同步进入阻塞态,然后发生进程切换。

  • Pend→Ready / Pend→Running:

    阻塞进程内的任意线程恢复就绪态时,进程被加入到就绪队列,同步转为就绪态,若此时发生进程切换,则进程状态由就绪态转为运行态。

  • Ready→Pend:

    进程内的最后一个就绪态线程处于阻塞态时,进程从就绪列表中删除,进程由就绪态转为阻塞态。

  • Running→Ready:

    进程由运行态转为就绪态的情况有以下两种:

    1. 有更高优先级的进程创建或者恢复后,会发生进程调度,此刻就绪列表中最高优先级进程变为运行态,那么原先运行的进程由运行态变为就绪态。
    2. 若进程的调度策略为SCHED_RR,且存在同一优先级的另一个进程处于就绪态,则该进程的时间片消耗光之后,该进程由运行态转为就绪态,另一个同优先级的进程由就绪态转为运行态。
  • Running→Zombies:

    当进程的主线程或所有线程运行结束后,进程由运行态转为僵尸态,等待父进程回收资源。

使用场景

进程创建后,用户只能操作自己进程空间的资源,无法操作其它进程的资源(共享资源除外)。用户态允许进程挂起,恢复,延时等操作,同时也可以设置用户态进程调度优先级和调度策略,获取进程调度优先级和调度策略。进程结束的时候,进程会主动释放持有的进程资源,但持有的进程pid资源需要父进程通过wait/waitpid或父进程退出时回收。

开始正式分析

对应张大爷的故事,进程就是那些在场馆外32个队列里排队的,那些队列就是进程的就绪队列。

请注意 进程是资源管理单元 ,而非最终调度单元,调度单元是谁?是 Task ,看下官方对应状态定义

#define OS_PROCESS_STATUS_INIT           0x0010U    //进程初始状态
#define OS_PROCESS_STATUS_READY          0x0020U    //进程就绪状态
#define OS_PROCESS_STATUS_RUNNING        0x0040U    //进程运行状态
#define OS_PROCESS_STATUS_PEND           0x0080U    //进程阻塞状态
#define OS_PROCESS_STATUS_ZOMBIES        0x100U     //进程僵死状态

一个进程从创建到消亡过程,在内核肯定是极其复杂的。为了方便理解进程,整个系列文章笔者会用张大爷的故事打比方,从生活中的例子来将神秘的系统内核外化解剖出来给大家看。一件这么复杂的事情肯定会有个复杂的结构体来承载,它就是LosProcessCB(进程控制块),代码很长但必须全部拿出来。


LITE_OS_SEC_BSS LosProcessCB *g_runProcess[LOSCFG_KERNEL_CORE_NUM]; //用一个指针数组记录进程运行,LOSCFG_KERNEL_CORE_NUM 为 CPU的核数
LITE_OS_SEC_BSS LosProcessCB *g_processCBArray = NULL;//进程池,最大进程数为 64个 
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_freeProcess;//记录空闲的进程链表
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_processRecyleList;//记录回收的进程列表typedef struct ProcessCB {CHAR                 processName[OS_PCB_NAME_LEN]; /**< Process name */ //进程名称UINT32               processID;                    /**< process ID = leader thread ID */ //进程ID,由进程池分配,范围[0,64]UINT16               processStatus;                /**< [15:4] process Status; [3:0] The number of threads currentlyrunning in the process *///这里设计很巧妙.用一个16表示了两层逻辑 数量和状态,点赞!UINT16               priority;                     /**< process priority */ //进程优先级UINT16               policy;                       /**< process policy */ //进程的调度方式,默认抢占式UINT16               timeSlice;                    /**< Remaining time slice *///进程时间片,默认2个tickUINT16               consoleID;                    /**< The console id of task belongs  *///任务的控制台id归属UINT16               processMode;                  /**< Kernel Mode:0; User Mode:1; */ //模式指定为内核还是用户进程UINT32               parentProcessID;              /**< Parent process ID */ //父进程IDUINT32               exitCode;                     /**< process exit status */ //进程退出状态码LOS_DL_LIST          pendList;                     /**< Block list to which the process belongs */ //进程所属的阻塞列表,如果因拿锁失败,就由此节点挂到等锁链表上LOS_DL_LIST          childrenList;                 /**< my children process list */ //孩子进程都挂到这里,形成双循环链表LOS_DL_LIST          exitChildList;                /**< my exit children process list */ //那些要退出孩子进程挂到这里,白发人送黑发人。LOS_DL_LIST          siblingList;                  /**< linkage in my parent's children list */ //兄弟进程链表, 56个民族是一家,来自同一个父进程.ProcessGroup         *group;                       /**< Process group to which a process belongs */ //所属进程组LOS_DL_LIST          subordinateGroupList;         /**< linkage in my group list */ //进程是组长时,有哪些组员进程UINT32               threadGroupID;                /**< Which thread group , is the main thread ID of the process */ //哪个线程组是进程的主线程IDUINT32               threadScheduleMap;            /**< The scheduling bitmap table for the thread group of theprocess */ //进程的各线程调度位图LOS_DL_LIST          threadSiblingList;            /**< List of threads under this process *///进程的线程(任务)列表LOS_DL_LIST          threadPriQueueList[OS_PRIORITY_QUEUE_NUM]; /**< The process's thread group schedules thepriority hash table */ //进程的线程组调度优先级哈希表volatile UINT32      threadNumber; /**< Number of threads alive under this process */ //此进程下的活动线程数UINT32               threadCount;  /**< Total number of threads created under this process */ //在此进程下创建的线程总数LOS_DL_LIST          waitList;     /**< The process holds the waitLits to support wait/waitpid *///进程持有等待链表以支持wait/waitpid
#if (LOSCFG_KERNEL_SMP == YES)UINT32               timerCpu;     /**< CPU core number of this task is delayed or pended *///统计各线程被延期或阻塞的时间
#endifUINTPTR              sigHandler;   /**< signal handler */ //信号处理函数,处理如 SIGSYS 等信号 sigset_t             sigShare;     /**< signal share bit */ //信号共享位
#if (LOSCFG_KERNEL_LITEIPC == YES)ProcIpcInfo         ipcInfo;       /**< memory pool for lite ipc */ //用于进程间通讯的虚拟设备文件系统,设备装载点为 /dev/lite_ipc
#endifLosVmSpace          *vmSpace;       /**< VMM space for processes */ //虚拟空间,描述进程虚拟内存的数据结构,linux称为内存描述符
#ifdef LOSCFG_FS_VFSstruct files_struct *files;        /**< Files held by the process */ //进程所持有的所有文件,注者称之为进程的文件管理器
#endif //每个进程都有属于自己的文件管理器,记录对文件的操作. 注意:一个文件可以被多个进程操作timer_t             timerID;       /**< iTimer */#ifdef LOSCFG_SECURITY_CAPABILITY //安全能力User                *user;  //进程的拥有者UINT32              capability; //安全能力范围 对应 CAP_SETGID
#endif
#ifdef LOSCFG_SECURITY_VIDTimerIdMap          timerIdMap;
#endif
#ifdef LOSCFG_DRIVERS_TZDRIVERstruct file         *execFile;     /**< Exec bin of the process */
#endifmode_t umask;
} LosProcessCB;

进程的模式有两种,内核态和用户态,能想到main函数中肯定会创建一个内核态的最高优先级进程,他就是 KProcess

通过task命令查看任务运行状态,可以看到 KProcess 进程 ,看名字就知道是一个内核进程,在系统启动时创建,图中可以看到 KProcesstask运行情况,从表里可以看到KProcess内有 10几个task

鸿蒙task

进程模块是如何初始化的

KProcess 在张大爷的故事里相当于场馆的工作人员,他们也要接受张大爷的调度排队进场,但他们的优先级是最高的0级,他们进场后需完成场馆的准备工作,再开门做生意。如果需要多个工作人员怎么办,就是通过fork,简单说就是复制一个,复制的前提是需要有一个,鸿蒙里就是KProcess,其他工作人员都是通过它fork的。
那用户怎么来的呢?就是真正要排队的人也是一样,先创建一个用户祖先,其他用户皆由祖先fork来的。
注意用户进程和内核进程的祖先是不一样的,有各自的祖先根.分别是g_userInitProcess(1号) 和 g_kernelInitProcess(2号)

/******************************************************************************并发(Concurrent):多个线程在单个核心运行,同一时间一个线程运行,系统不停切换线程,看起来像同时运行,实际上是线程不停切换并行(Parallel)每个线程分配给独立的CPU核心,线程同时运行单核CPU多个进程或多个线程内能实现并发(微观上的串行,宏观上的并行)多核CPU线程间可以实现宏观和微观上的并行LITE_OS_SEC_BSS 和 LITE_OS_SEC_DATA_INIT 是告诉编译器这些全局变量放在哪个数据段
******************************************************************************/
LITE_OS_SEC_BSS LosProcessCB *g_runProcess[LOSCFG_KERNEL_CORE_NUM];// CPU内核个数,超过一个就实现了并行
LITE_OS_SEC_BSS LosProcessCB *g_processCBArray = NULL; // 进程池数组
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_freeProcess;// 空闲状态下的进程链表, .个人觉得应该取名为 g_freeProcessList  @note_thinking
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_processRecyleList;// 需要回收的进程列表
LITE_OS_SEC_BSS UINT32 g_userInitProcess = OS_INVALID_VALUE;// 用户态的初始init进程,用户态下其他进程由它 fork
LITE_OS_SEC_BSS UINT32 g_kernelInitProcess = OS_INVALID_VALUE;// 内核态初始Kprocess进程,内核态下其他进程由它 fork
LITE_OS_SEC_BSS UINT32 g_kernelIdleProcess = OS_INVALID_VALUE;// 内核态idle进程,由Kprocess fork
LITE_OS_SEC_BSS UINT32 g_processMaxNum;// 进程最大数量,默认64个
LITE_OS_SEC_BSS ProcessGroup *g_processGroup = NULL;// 全局进程组,负责管理所有进程组//进程模块初始化,被编译放在代码段 .init 中
LITE_OS_SEC_TEXT_INIT UINT32 OsProcessInit(VOID)
{UINT32 index;UINT32 size;g_processMaxNum = LOSCFG_BASE_CORE_PROCESS_LIMIT;//默认支持64个进程size = g_processMaxNum * sizeof(LosProcessCB);//算出总大小g_processCBArray = (LosProcessCB *)LOS_MemAlloc(m_aucSysMem1, size);// 进程池,占用内核堆,内存池分配 if (g_processCBArray == NULL) {return LOS_NOK;}(VOID)memset_s(g_processCBArray, size, 0, size);//安全方式重置清0LOS_ListInit(&g_freeProcess);//进程空闲链表初始化,创建一个进程时从g_freeProcess中申请一个进程描述符使用LOS_ListInit(&g_processRecyleList);//进程回收链表初始化,回收完成后进入g_freeProcess等待再次被申请使用for (index = 0; index < g_processMaxNum; index++) {//进程池循环创建g_processCBArray[index].processID = index;//进程ID[0-g_processMaxNum]赋值g_processCBArray[index].processStatus = OS_PROCESS_FLAG_UNUSED;// 默认都是白纸一张,贴上未使用标签LOS_ListTailInsert(&g_freeProcess, &g_processCBArray[index].pendList);//注意g_freeProcess挂的是pendList节点,所以使用要通过OS_PCB_FROM_PENDLIST找到进程实体.}g_userInitProcess = 1; /* 1: The root process ID of the user-mode process is fixed at 1 *///用户模式的根进程LOS_ListDelete(&g_processCBArray[g_userInitProcess].pendList);// 清空g_userInitProcess pend链表g_kernelInitProcess = 2; /* 2: The root process ID of the kernel-mode process is fixed at 2 *///内核模式的根进程LOS_ListDelete(&g_processCBArray[g_kernelInitProcess].pendList);// 清空g_kernelInitProcess pend链表return LOS_OK;
}

代码已经很清楚,创建了一个进程池,默认64个进程,也就是不改宏LOSCFG_BASE_CORE_PROCESS_LIMIT的情况下 系统最多是64个进程,但有两个进程先被占用,用户态和内核态各一个,他们是后续创建进程的根,所以最多留给外面的只有 62个进程可创建,代码的最后两个根进程的task阻塞链表被清空了,因为没有阻塞任务当然要清空.

内核态根进程创建过程

创建"Kprocess"进程,也就是线程池中的2号进程g_kernelInitProcess,设为最高优先级 0

//初始化 2号进程,即内核根进程
LITE_OS_SEC_TEXT_INIT UINT32 OsKernelInitProcess(VOID)
{LosProcessCB *processCB = NULL;UINT32 ret;ret = OsProcessInit();// 初始化进程模块全部变量,创建各循环双向链表if (ret != LOS_OK) {return ret;}processCB = OS_PCB_FROM_PID(g_kernelInitProcess);// 以PID方式得到一个进程ret = OsProcessCreateInit(processCB, OS_KERNEL_MODE, "KProcess", 0);// 初始化进程,最高优先级0,鸿蒙进程一共有32个优先级(0-31) 其中0-9级为内核进程,用户进程可配置的优先级有22个(10-31)if (ret != LOS_OK) {return ret;}processCB->processStatus &= ~OS_PROCESS_STATUS_INIT;// 进程初始化位 置1g_processGroup = processCB->group;//全局进程组指向了KProcess所在的进程组LOS_ListInit(&g_processGroup->groupList);// 进程组链表初始化OsCurrProcessSet(processCB);// 设置为当前进程return OsCreateIdleProcess();// 创建一个空闲状态的进程
}//创建一个名叫"KIdle"的进程,给CPU空闲的时候使用
STATIC UINT32 OsCreateIdleProcess(VOID)
{UINT32 ret;CHAR *idleName = "Idle";LosProcessCB *idleProcess = NULL;Percpu *perCpu = OsPercpuGet();UINT32 *idleTaskID = &perCpu->idleTaskID;//得到CPU的idle taskret = OsCreateResourceFreeTask();// 创建一个资源回收任务,优先级为5 用于回收进程退出时的各种资源if (ret != LOS_OK) {return ret;}//创建一个名叫"KIdle"的进程,并创建一个idle task,CPU空闲的时候就待在 idle task中等待被唤醒ret = LOS_Fork(CLONE_FILES, "KIdle", (TSK_ENTRY_FUNC)OsIdleTask, LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE);if (ret < 0) {return LOS_NOK;}g_kernelIdleProcess = (UINT32)ret;//返回进程IDidleProcess = OS_PCB_FROM_PID(g_kernelIdleProcess);//通过ID拿到进程实体*idleTaskID = idleProcess->threadGroupID;//绑定CPU的IdleTask,或者说改变CPU现有的idle任务OS_TCB_FROM_TID(*idleTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK;//设定Idle task 为一个系统任务
#if (LOSCFG_KERNEL_SMP == YES)OS_TCB_FROM_TID(*idleTaskID)->cpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());//多核CPU的任务指定,防止乱串了,注意多核才会有并行处理
#endif(VOID)memset_s(OS_TCB_FROM_TID(*idleTaskID)->taskName, OS_TCB_NAME_LEN, 0, OS_TCB_NAME_LEN);//task 名字先清0(VOID)memcpy_s(OS_TCB_FROM_TID(*idleTaskID)->taskName, OS_TCB_NAME_LEN, idleName, strlen(idleName));//task 名字叫 idlereturn LOS_OK;
}

用户态根进程创建过程

创建Init进程,也就是线程池中的1号进程g_userInitProcess,优先级为 28,好低啊

/*** @ingroup los_process* User state root process default priority*/
#define OS_PROCESS_USERINIT_PRIORITY     28//所有的用户进程都是使用同一个用户代码段描述符和用户数据段描述符,它们是__USER_CS和__USER_DS,也就是每个进程处于用户态时,它们的CS寄存器和DS寄存器中的值是相同的。当任何进程或者中断异常进入内核后,都是使用相同的内核代码段描述符和内核数据段描述符,它们是__KERNEL_CS和__KERNEL_DS。这里要明确记得,内核数据段实际上就是内核态堆栈段。
LITE_OS_SEC_TEXT_INIT UINT32 OsUserInitProcess(VOID)
{INT32 ret;UINT32 size;TSK_INIT_PARAM_S param = { 0 };VOID *stack = NULL;VOID *userText = NULL;CHAR *userInitTextStart = (CHAR *)&__user_init_entry;//代码区开始位置 ,所有进程CHAR *userInitBssStart = (CHAR *)&__user_init_bss;// 未初始化数据区(BSS)。在运行时改变其值CHAR *userInitEnd = (CHAR *)&__user_init_end;// 结束地址UINT32 initBssSize = userInitEnd - userInitBssStart;UINT32 initSize = userInitEnd - userInitTextStart;LosProcessCB *processCB = OS_PCB_FROM_PID(g_userInitProcess);ret = OsProcessCreateInit(processCB, OS_USER_MODE, "Init", OS_PROCESS_USERINIT_PRIORITY);// 初始化用户进程,它将是所有应用程序的父进程if (ret != LOS_OK) {return ret;}userText = LOS_PhysPagesAllocContiguous(initSize >> PAGE_SHIFT);// 分配连续的物理页if (userText == NULL) {ret = LOS_NOK;goto ERROR;}(VOID)memcpy_s(userText, initSize, (VOID *)&__user_init_load_addr, initSize);// 安全copy 经加载器load的结果 __user_init_load_addr -> userTextret = LOS_VaddrToPaddrMmap(processCB->vmSpace, (VADDR_T)(UINTPTR)userInitTextStart, LOS_PaddrQuery(userText),initSize, VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE |VM_MAP_REGION_FLAG_PERM_EXECUTE | VM_MAP_REGION_FLAG_PERM_USER);// 虚拟地址与物理地址的映射if (ret < 0) {goto ERROR;}(VOID)memset_s((VOID *)((UINTPTR)userText + userInitBssStart - userInitTextStart), initBssSize, 0, initBssSize);// 除了代码段,其余都清0stack = OsUserInitStackAlloc(g_userInitProcess, &size);// 初始化堆栈区if (stack == NULL) {PRINTK("user init process malloc user stack failed!\n");ret = LOS_NOK;goto ERROR;}param.pfnTaskEntry = (TSK_ENTRY_FUNC)userInitTextStart;// 从代码区开始执行,也就是应用程序main 函数的位置param.userParam.userSP = (UINTPTR)stack + size;// 指向栈顶param.userParam.userMapBase = (UINTPTR)stack;// 栈底param.userParam.userMapSize = size;// 栈大小param.uwResved = OS_TASK_FLAG_PTHREAD_JOIN;// 可结合的(joinable)能够被其他线程收回其资源和杀死ret = OsUserInitProcessStart(g_userInitProcess, &param);// 创建一个任务,来运行main函数if (ret != LOS_OK) {(VOID)OsUnMMap(processCB->vmSpace, param.userParam.userMapBase, param.userParam.userMapSize);goto ERROR;}return LOS_OK;ERROR:(VOID)LOS_PhysPagesFreeContiguous(userText, initSize >> PAGE_SHIFT);//释放物理内存块OsDeInitPCB(processCB);//删除PCB块return ret;
}

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

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

开发基础知识:https://qr21.cn/FV7h05

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

基于ArkTS 开发:https://qr21.cn/FV7h05

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

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

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

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

相关文章

yolov8旋转目标检测输出的角度转化为适合机械爪抓取的角度

1. 机械爪抓取时旋转的角度定义 以X轴正方向&#xff08;右&#xff09;为零度方向&#xff0c;角度取值范围[-90&#xff0c;90)。 确认角度的方法&#xff1a; 逆时针旋转X轴&#xff0c;X轴碰到矩形框长边时旋转过的角度记为angleX&#xff1a; 1.如果angleX小于90&#xf…

【源码】IM即时通讯源码/H5聊天软件/视频通话+语音通话/带文字部署教程

【源码介绍】 IM即时通讯源码/H5聊天软件/视频通话语音通话/带文字部署教程 【源码说明】 测试环境&#xff1a;Linux系统CentOS7.6、宝塔、PHP7.2、MySQL5.6&#xff0c;根目录public&#xff0c;伪静态laravel5&#xff0c;根据情况开启SSL 登录后台看到很熟悉。。原来是…

docker容器技术篇:集群管理实战mesos+zookeeper+marathon(二)

docker集群管理实战mesoszookeepermarathon&#xff08;二&#xff09; 一 实验环境 操作系统&#xff1a;centos7.9 二 基础环境配置以及安装mesos 安装过程请点击下面的链接查看&#xff1a; 容器集群管理实战mesoszookeepermarathon&#xff08;一&#xff09; 三 安装…

STM32进入睡眠模式的方法

#STM32进入睡眠模式的方法 今天学习了如何控制STM32进入睡眠模式&#xff0c;进入睡眠模式的好处就是省电&#xff0c;今天学习的只是浅度睡眠&#xff0c;通过中断就能唤醒。比如单片机在那一放&#xff0c;也许好几天好几个月都不用一次&#xff0c;整天的在那空跑while循环…

Git重修系列 ------ Git的使用和常用命令总结

一、Git的安装和配置 git安装&#xff1a; Git - Downloads git首次配置用户信息&#xff1a; $ git config --global user.name "kequan" $ git config --global user.email kequanchanqq.com $ git config --global credential store 配置 Git 以使用本地存储机…

鸿蒙OpenHarmony【小型系统 编译】(基于Hi3516开发板)

编译 OpenHarmony支持hb和build.sh两种编译方式。此处介绍hb方式&#xff0c;build.sh脚本编译方式请参考[使用build.sh脚本编译源码]。 使用build.sh脚本编译源码 进入源码根目录&#xff0c;执行如下命令进行版本编译。 ./build.sh --product-name name --ccache 说明&…

刷机维修进阶教程---开机定屏 红字感叹号报错 写字库保资料 救砖 刷官方包保资料的步骤方法解析

在维修各种机型 中经常会遇到开机定屏 进不去系统,正常使用无故定屏进不去系统或者更新降级开机红色感叹号的一些故障机。但顾客需要报资料救砖的要求,遇到这种情况。我们首先要确定故障机型的缘由。是摔 还是更新降级 还是无故使用重启定屏等等。根据原因来对症解决。 通过…

Tiny11作者开源:利用微软官方镜像制作独属于你的Tiny11镜像

微软对Windows 11的最低硬件要求包括至少4GB的内存、双核处理器和64GB的SSD存储。然而&#xff0c;这些基本要求仅仅能保证用户启动和运行系统&#xff0c;而非流畅使用 为了提升体验&#xff0c;不少用户选择通过精简系统来减轻硬件负担&#xff0c;我们熟知的Tiny11便是其中…

Typora for Mac:轻量级Markdown编辑器

Typora for Mac是一款专为Mac用户设计的轻量级Markdown编辑器&#xff0c;它以其简洁的界面和强大的功能&#xff0c;成为了Markdown写作爱好者的首选工具。 Typora for Mac v1.8.10中文激活版下载 Typora的最大特色在于其所见即所得的编辑模式&#xff0c;用户无需关心复杂的M…

(七)Servlet教程——Idea编辑器集成Tomcat

1. 点击桌面上Idea快捷方式打开Idea编辑器&#xff0c;假如没有创建项目的话打开Idea编辑器后的界面展示如下图所示 2. 点击界面左侧菜单中的自定义 3. 然后点击界面中的“所有设置...”,然后点击“构建、执行、部署”&#xff0c;选择其中的“应用程序服务器” 4. 点击“”按钮…

Centos之yum安装好玩的命令

1.会动的小火车 我在root下使用的 yum install sl.x86_64sl2.figlet yum install figlet.x86_64figlet 55553.cowsay会说话 yum install cowsay

前端HTML5学习2(新增多媒体标签,H5的兼容性处理)

前端HTML5学习2新增多媒体标签&#xff0c;H5的兼容性处理&#xff09; 分清标签和属性新增多媒体标签新增视频标签新增音频标签新增全局属性 H5的兼容性处理 分清标签和属性 标签&#xff08;HTML元素&#xff09;和属性&#xff0c;标签定义了内容的类型或结构&#xff0c;而…

CSS3(响应式布局)

#过渡# 属性连写&#xff1a; transition: width 2s linear 1s; //前一个时间用于表示过渡效果持续时间&#xff0c;后一个时间用于表示过渡效果的延迟。 #转换# #2D转换# 和 #3D转换# 注意&#xff1a;其中angle对应单位为&#xff1a;deg #圆角# #边框# …

RabbitMQ知识点总结(一)

为什么要使用RabbitMQ? 异步&#xff0c;解耦&#xff0c;削峰。 异步 提高效率&#xff1b;一个挂了&#xff0c;另外的服务不受影响。 解耦 增加或减少服务比较方便。 削峰 每天0点到16点&#xff0c;A系统风平浪静&#xff0c;每秒并发数量就100个。结果每次到了16点到…

大语言模型Ollama

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Ollama简介 Ollama是一个开源的大语言模型平台&#xff0c;它允许用户在本地环境中运行、创建和共享大型语言模型。Ollama提供了丰富的功能和特性&#xff0c;使得用户可以…

rabbitmq下载安装最新版本--并添加开机启动图文详解!!

一、简介 RabbitMQ是一个开源的遵循AMQP协议实现的消息中间件支持多种客户端语言,用于分布式系统中存储和转发消息, 这是 Release RabbitMQ 3.13.0 rabbitmq/rabbitmq-server GitHub 二、安装前准备 1、查看自己系统 确认操作系统版本兼容性 uname -a2、下载Erlang依赖包…

Cesium.js(3):Cesium查看器、场景、实体、数据源介绍

1 Cesium的四大类说明 1.1 Viewer查看器类 Viewer是cesium的查看器类&#xff0c;第一个参数是地图主窗口DIV的容器ID&#xff0c;第二个参数option是Viewer的可选设置参数&#xff0c;包含图层、地形时间系统等参数&#xff0c;种类多样&#xff0c;主要作用是对视口中各个组…

unity 专项一 localPosition与anchoredPosition(3D)的区别

一 、RectTransform 概念 1、RectTransform继承自Transform&#xff0c;用于描述矩形的坐标(Position)&#xff0c;尺寸(Size)&#xff0c;锚点(anchor)和中心点(pivot)等信息&#xff0c;每个2D布局下的元素都会自动生成该组件。 2、当我们在处理UI组件时&#xff0c;往往容易…

typescript:vscode的settings配置文件配置ts语法提示

typescript&#xff1a;vscode的settings配置文件配置ts语法提示 1 找到vscode左下角的齿轮按钮 2 点击Settings&#xff08;或者快捷键ctrl,&#xff09;&#xff1a; 点击右上角的Open Settings(JSON)按钮打开配置文件&#xff1a; 或者ctrlshiftp&#xff0c;搜索settings&…

【uniapp/ucharts】采用 uniapp 框架的 h5 应用使用 ucharts(没有 uni_modules)

这种情况无法直接从 dcloud 平台上一键下载导入&#xff0c;所以应该在官网推荐的 git 仓库去单独下载&#xff1a; https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6/qiun-data-charts(%E9%9D%9Euni_modules) 下载的文件是如图所示的路径&…