鸿蒙内核源码分析 (并发并行篇) | 内核如何管理多个 CPU?

理解并发概念

  • 并发(Concurrent): 多个线程在单个核心运行,同一时间只能一个线程运行,内核不停切换线程,看起来像同时运行,实际上是线程被高速的切换.

  • 通俗好理解的比喻就是高速单行道,单行道指的是 CPU 的核数,跑的车就是线程 (任务),进程就是管理车的公司,一个公司可以有很多台车。并发和并行跟 CPU 的核数有关。车道上同时只能跑一辆车,但因为指挥系统很牛,够快,在毫秒级内就能换车跑,人根本感知不到切换。所以外部的感知会是同时在进行,实现了微观上的串行,宏观上的并行.

线程切换的本质是 CPU 要换场地上班,去哪里上班由哪里提供场地,那个场地就是任务栈,每个任务栈中保存了上班的各种材料,来了就行立马干活。那些材料就是任务上下文。简单的说就是上次活干到那里了,回来继续接着干。上下文由任务栈自己保存,CPU 不管的,它来了只负责任务交过来的材料,材料显示去哪里搬砖它就去哪里搬砖.

记住一个单词就能记住并行并发的区别, 发单,发单 (并发单行).

理解并行概念

并行(Parallel)每个线程分配给独立的 CPU 核心,线程真正的同时运行.

通俗好理解的比喻就是高速多行道,实现了微观和宏观上同时进行。并行当然是快,人多了干活就不那么累,但干活人多了必然会带来人多的管理问题,会把问题变复杂,请想想会出现哪些问题?

理解协程概念

这里说下协程,例如 go 语言是有协程支持的,其实协程跟内核层没有关系,是应用层的概念。是在线程之上更高层的封装,用通俗的比喻来说就是在车内另外搞了几条车道玩。其对内核来说没有新东西,内核只负责车的调度,至于车内你想怎么弄那是应用程序自己的事。本质的区别是 CPU 根本没有换地方上班 (没有被调度),而并发 / 并行都是换地方上班了.

内核如何描述 CPU

    typedef struct {SortLinkAttribute taskSortLink;             /* task sort link */ //每个CPU core 都有一个task排序链表SortLinkAttribute swtmrSortLink;            /* swtmr sort link */ //每个CPU core 都有一个定时器排序链表UINT32 idleTaskID;                          /* idle task id */  //空闲任务ID 见于 OsIdleTaskCreateUINT32 taskLockCnt;                         /* task lock flag */ //任务锁的数量,当 > 0 的时候,需要重新调度了UINT32 swtmrHandlerQueue;                   /* software timer timeout queue id */ //软时钟超时队列句柄UINT32 swtmrTaskID;                         /* software timer task id */ //软时钟任务IDUINT32 schedFlag;                           /* pending scheduler flag */ //调度标识 INT_NO_RESCH INT_PEND_RESCH#if (LOSCFG_KERNEL_SMP == YES)UINT32 excFlag;                             /* cpu halt or exc flag */ //CPU处于停止或运行的标识#endif} Percpu;Percpu g_percpu[LOSCFG_KERNEL_CORE_NUM];//全局CPU数组

这是内核对 CPU 的描述,主要是两个排序链表,一个是任务的排序,一个是定时器的排序。什么意思?在系列篇中多次提过,任务是内核的调度单元,注意可不是进程,虽然调度也需要进程参与,也需要切换进程,切换用户空间。但调度的核心是切换任务,每个任务的代码指令才是 CPU 的粮食,它吃的是一条条的指令。每个任务都必须指定取粮地址 (即入口函数).

另外还有一个东西能提供入口函数,就是定时任务。很重要也很常用,没它某宝每晚 9 点的准时秒杀实现不了。在内核每个 CPU 都有自己独立的任务和定时器链表.

每次 Tick 的到来,处理函数会去扫描这两个链表,看有没有定时器超时的任务需要执行,有则立即执行定时任务,定时任务是所有任务中优先级最高的,0 号优先级,在系列篇中有专门讲定时器任务,可自行翻看.

LOSCFG_KERNEL_SMP

# if (LOSCFG_KERNEL_SMP == YES)
# define LOSCFG_KERNEL_CORE_NUM                          LOSCFG_KERNEL_SMP_CORE_NUM //多核情况下支持的CPU核数
# else
# define LOSCFG_KERNEL_CORE_NUM                          1 //单核配置
# endif

多 CPU 核的操作系统有 3 种处理模式 (SMP+AMP+BMP) 鸿蒙实现的是 SMP 的方式

  • 非对称多处理(Asymmetric multiprocessing,AMP)每个 CPU 内核运行一个独立的操作系统或同一操作系统的独立实例(instantiation)。
  • 对称多处理(Symmetric multiprocessing,SMP)一个操作系统的实例可以同时管理所有 CPU 内核,且应用并不绑定某一个内核。
  • 混合多处理(Bound multiprocessing,BMP)一个操作系统的实例可以同时管理所有 CPU 内核,但每个应用被锁定于某个指定的核心。

宏 LOSCFG_KERNEL_SMP 表示对多 CPU 核的支持,鸿蒙默认是打开 LOSCFG_KERNEL_SMP 的。

多 CPU 核支持

鸿蒙内核对 CPU 的操作见于 los_mp.c ,因文件不大,这里把代码都贴出来了.

    #if (LOSCFG_KERNEL_SMP == YES)//给参数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}//硬中断唤醒处理函数VOID OsMpWakeHandler(VOID){/* generic wakeup ipi, do nothing */}//硬中断调度处理函数VOID OsMpScheduleHandler(VOID){//将调度标志设置为与唤醒功能不同,这样就可以在硬中断结束时触发调度程序。/** set schedule flag to differ from wake function,* so that the scheduler can be triggered at the end of irq.*/OsPercpuGet()->schedFlag = INT_PEND_RESCH;//给当前Cpu贴上调度标签}//硬中断暂停处理函数VOID OsMpHaltHandler(VOID){(VOID)LOS_IntLock();OsPercpuGet()->excFlag = CPU_HALT;//让当前Cpu停止工作while (1) {}//陷入空循环,也就是空闲状态}//MP定时器处理函数, 递归检查所有可用任务VOID OsMpCollectTasks(VOID){LosTaskCB *taskCB = NULL;UINT32 taskID = 0;UINT32 ret;/* recursive checking all the available task */for (; taskID <= g_taskMaxNum; taskID++) { //递归检查所有可用任务taskCB = &g_taskCBArray[taskID];if (OsTaskIsUnused(taskCB) || OsTaskIsRunning(taskCB)) {continue;}/* 虽然任务状态不是原子的,但此检查可能成功,但无法完成删除,此删除将在下次运行之前处理* though task status is not atomic, this check may success but not accomplish* the deletion; this deletion will be handled until the next run.*/if (taskCB->signal & SIGNAL_KILL) {//任务收到被干掉信号ret = LOS_TaskDelete(taskID);//干掉任务,回归任务池if (ret != LOS_OK) {PRINT_WARN("GC collect task failed err:0x%x\n", ret);}}}}//MP(multiprocessing) 多核处理器初始化UINT32 OsMpInit(VOID){UINT16 swtmrId;(VOID)LOS_SwtmrCreate(OS_MP_GC_PERIOD, LOS_SWTMR_MODE_PERIOD, //创建一个周期性,持续时间为 100个tick的定时器(SWTMR_PROC_FUNC)OsMpCollectTasks, &swtmrId, 0);//OsMpCollectTasks为超时回调函数(VOID)LOS_SwtmrStart(swtmrId);//开始定时任务return LOS_OK;}#endif

代码一一都加上了注解,这里再一一说明下:

1.OsMpInit

多 CPU 核的初始化, 多核情况下每个 CPU 都有各自的编号, 内核有分成主次 CPU, 0 号默认为主 CPU, OsMain () 由主 CPU 执行,被汇编代码调用。初始化只开了个定时任务,只干一件事就是回收不用的任务。回收的条件是任务是否收到了被干掉的信号。例如 shell 命令 kill 9 14 ,意思是干掉 14 号线程的信号,这个信号会被线程保存起来。可以选择自杀也可以等着被杀。这里要注意,鸿蒙有两种情况下任务不能被干掉, 一种是系统任务不能被干掉的, 第二种是正在运行状态的任务.

2. 次级 CPU 的初始化

同样由汇编代码调用,通过以下函数执行,完成每个 CPU 核的初始化

    //次级CPU初始化,本函数执行的次数由次级CPU的个数决定. 例如:在四核情况下,会被执行3次, 0号通常被定义为主CPU 执行mainLITE_OS_SEC_TEXT_INIT VOID secondary_cpu_start(VOID){#if (LOSCFG_KERNEL_SMP == YES)UINT32 cpuid = ArchCurrCpuid();OsArchMmuInitPerCPU();//每个CPU都需要初始化MMUOsCurrTaskSet(OsGetMainTask());//设置CPU的当前任务/* increase cpu counter */LOS_AtomicInc(&g_ncpu); //统计CPU的数量/* store each core's hwid */CPU_MAP_SET(cpuid, OsHwIDGet());//存储每个CPU的 hwidHalIrqInitPercpu(); //CPU硬件中断初始化OsCurrProcessSet(OS_PCB_FROM_PID(OsGetKernelInitProcessID())); //设置内核进程为CPU进程OsSwtmrInit();  //定时任务初始化,每个CPU维护自己的定时器队列OsIdleTaskCreate(); //创建空闲任务,每个CPU维护自己的任务队列OsStart(); //本CPU正式启动在内核层的工作while (1) {__asm volatile("wfi");//wait for Interrupt 等待中断,即下一次中断发生前都在此hold住不干活}//类似的还有 WFE: wait for Events 等待事件,即下一次事件发生前都在此hold住不干活#endif}

可以看出次级 CPU 有哪些初始化步骤:

  • 初始化 MMU,OsArchMmuInitPerCPU
  • 设置当前任务 OsCurrTaskSet
  • 初始化硬件中断 HalIrqInitPercpu
  • 初始化定时器队列 OsSwtmrInit
  • 创建空任务 OsIdleTaskCreate, 外面没有任务的时 CPU 就待在这个空任务里自己转圈圈.
  • 开始自己的工作流程 OsStart,正式开始工作,跑任务

为了能让大家更好的学习鸿蒙(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.hqwc.cn/news/598254.html

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

相关文章

AI预测福彩3D第28弹【2024年4月6日预测--第7套算法重新开始计算第1次测试】

今天开始&#xff0c;咱们开始进行第7套算法的测试&#xff0c;第7套算法将综合012路权重、012路直选及012路和值进行预测。好了&#xff0c;先上图后上结果吧~ 2024年4月6日福彩3D的七码预测结果如下 第一套&#xff1a; 百位&#xff1a;1 2 4 5 7 8…

计算机视觉入门:开启图像理解之旅

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向的学习指导…

使用 Docker 部署 Photopea 在线 PS 工具

1&#xff09;Photopea 介绍 GitHub&#xff1a;https://github.com/photopea/photopea 官方手册&#xff1a;https://www.photopea.com/learn/ Adobe 出品的「PhotoShop」想必大家都很熟悉啦&#xff0c;但是「PhotoShop」现在对电脑配置要求越来越高&#xff0c;体积越来越大…

JavaEE初阶——多线程(一)

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享多线程的第一部分:引入线程以及创建多线程的几种方式 此文章是建立在前一篇文章进程的基础上的 如果有不足的或者错误的请您指出! 1.认识线程 我们知道现代的cpu大多都是多核心…

5.3 用栈翻转数组,动态规划求斐波那契数列

5.3 用栈翻转数组&#xff0c;动态规划求斐波那契数列 1. 用栈翻转数组 assume cs:code,ds:data,ss:stack data segmentarr dw 1111h,2222h,3333h,4444h,5555h,6666h,7777h,8888hres db 800 dup(0) data endsstack segmentdb 100 dup(0) stack endscode segmentstart:mov ax,…

xss.pwnfunction-Jefff

在eval中可以直接执行命令所以直接把"直接闭合在结尾再加上一个"因为后面的"没闭和会报错 ?jeffa";alert(1);" 或 ?jeffa"-alert(1)-" -是分隔符

文本识别 OCR 解决方案

Capture2Text 便携式 OCR 工具 Capture2Text 能够使用键盘快捷键快速对屏幕的一部分进行 OCR。 默认情况下&#xff0c;生成的文本将保存到剪贴板。支持中文、英文、法文、德文、日文、韩文、俄文、西班牙文等 90 多种语言。 Capture2Text 是便携式工具&#xff0c;不需要安装…

maven jar 加载完毕后代码依旧报错提示 Cannot resolve symbol ‘Service‘ xxx

点击菜单中的 “File” -> “Invalidate Caches / Restart”→ “Invalidate and Restart”&#xff0c;清空 cache 并且重启。

QA测试开发工程师面试题满分问答10: python提供的内置类型有哪些(可变和不可变类型)

Python提供的内置类型可以按照可变&#xff08;mutable&#xff09;和不可变&#xff08;immutable&#xff09;类型进行分类。可变类型是指对象在创建后可以被修改&#xff0c;而不可变类型是指对象在创建后不能被修改。下面是按照可变和不可变类型分类的一些常见内置类型及其…

[StartingPoint][Tier1]Responder

Important 由于靶机IP是动态的,所以这里需要手动解析 # echo "<靶机IP> unika.htb">>/etc/hosts //10.10.16.59/testshare到底是什么? SMB&#xff08;Server Message Block&#xff09;是一种用于在计算机之间共享文件、打印机和其他资源的网络协议&…

性能分析--内存知识

内存相关知识 计算机中与CPU进行数据交换的桥梁。内存的速度&#xff0c;比CPU的速度要慢很多。比磁盘速度要快很多。内存中存放数据&#xff0c;一旦断电就会消失。linux系统的 /proc路径下的文件&#xff0c;都是内存文件。内存大小&#xff0c;一般 是GB为单位。 现在都操作…