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

news2025/1/31 3:15:48

理解并发概念

  • 并发(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 见于 OsIdleTaskCreate
        UINT32 taskLockCnt;                         /* task lock flag */ //任务锁的数量,当 > 0 的时候,需要重新调度了
        UINT32 swtmrHandlerQueue;                   /* software timer timeout queue id */ //软时钟超时队列句柄
        UINT32 swtmrTaskID;                         /* software timer task id */ //软时钟任务ID

        UINT32 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);//获取除了自身之外的其他CPU
        HalIrqSendIpi(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 执行main
    LITE_OS_SEC_TEXT_INIT VOID secondary_cpu_start(VOID)
    {
    #if (LOSCFG_KERNEL_SMP == YES)
        UINT32 cpuid = ArchCurrCpuid();

        OsArchMmuInitPerCPU();//每个CPU都需要初始化MMU

        OsCurrTaskSet(OsGetMainTask());//设置CPU的当前任务

        /* increase cpu counter */
        LOS_AtomicInc(&g_ncpu); //统计CPU的数量

        /* store each core's hwid */
        CPU_MAP_SET(cpuid, OsHwIDGet());//存储每个CPU的 hwid
        HalIrqInitPercpu(); //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.coloradmin.cn/o/1575617.html

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

相关文章

通过 Cookie、Redis共享Session 和 Spring 拦截器技术,实现对用户登录状态的持有和清理(三)

本篇内容对应 “2.4 生成验证码” 小节 和 “4.7 优化登陆模块”小节 视频链接 1 Kaptcha介绍 Kaotcga是一个生成验证码的工具。 你的网站验证码是什么&#xff1f; 在我们这个牛客论坛项目&#xff0c;验证码分为两部分 给用户看的是图片&#xff0c;用户根据图片上显示的…

js中获取某年到某年季度数据

1.新建文件 在utils文件夹下新建文件handleQuarterData.js用于封装 // startYear&#xff1a;开始年份 // endYear&#xff1a;结束年份 // 数据格式为&#xff1a;2024第一季度 export function getQuarterData(startYear, endYear) {const result [];const quarterMap [一…

【Java网络编程】计算机网络基础概念

就目前而言&#xff0c;多数网络编程的系列的文章都在围绕着计算机网络体系进行阐述&#xff0c;但其中太多理论概念&#xff0c;对于大部分开发者而言&#xff0c;用途甚微。因此&#xff0c;在本系列中则会以实际开发者的工作为核心&#xff0c;从Java程序员的角度出发&#…

[lesson10]C++中的新成员

C中的新成员 动态内存分配 C中的动态内存分配 C中通过new关键字进行动态内存申请C中的动态内存申请是基于类型进行的delete关键字用于内存释放 new关键字与malloc函数的区别 new关键字是C的一部分malloc是由C库提供的函数new以具体类型位单位进行内存分配malloc以字节位单位…

k8s1(1),Linux运维基础开发与实践

#设置主机名 hostnamectl hostnameXXX #配置免密(包括操作机) ssh-keygen ssh-copy-id master*/slave* #传输hosts cat > /etc/hosts <<EOF 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain loca…

线程安全性问题的原因

1.抢占式执行随机调度 这里的意思就是&#xff0c;当两个线程同时启动的时候&#xff0c;两个线程会同时进行&#xff0c;并且是抢占式执行的。 而且是随机调度资源的。 如代码&#xff1a; public class Deome4 {public static void main(String[] args) {Thread t1 new …

Kubesphere在创建服务的添加容器步骤搜索镜像步骤找不到镜像

Kubesphere在创建服务的添加容器步骤搜索镜像步骤找不到镜像 {"status": "failed","message": "invalid character p after top-level value" }添加了标签也没用&#xff08;如&#xff1a;mysql:5.7&#xff09; 可以看到 dockerhu…

AI颠覆职场:这些行业将被重塑,你准备好了吗?

人工智能&#xff08;AI&#xff09;已经成为我们生活中不可或缺的一部分。从智能手机到自动驾驶汽车&#xff0c;AI技术的应用无处不在。然而&#xff0c;这股技术浪潮也引发了一个问题&#xff1a;哪些行业将面临被AI替代的风险&#xff1f;本文将深入探讨这一问题&#xff0…

C++进阶(五) 哈希

1. unordered系列关联式容器 1.1 unordered_map 1.2 unordered_map的接口说明 2. 底层结构 2.1 哈希概念 2.2 哈希冲突 2.3 哈希函数 2.4 哈希冲突解决 2.4.1 闭散列 2.4.2 开散列 3. 模拟实现 3.1 unordered_set 3.2 unordered_map 4.哈希的应用 4.1 位图 4.1.…

阿里千问大模型 Qwen1.5 开源 32B 模型,将开源进行到底!!!

阿里开源的千问系列模型&#xff0c;一直受到业界好评&#xff0c;之前版本有0.5B、1.8B、7B、14B、72B&#xff0c;但一直缺少的30B级别开源模型&#xff0c;这也一直是一个遗憾。 怎么说呢&#xff1f;72B模型太大&#xff0c;很多人用不起来&#xff0c;无论是微调&#xf…

线程池小项目【Linux C/C++】(踩坑分享)

目录 前提知识&#xff1a; 一&#xff0c;线程池意义 二&#xff0c;实现流程 阶段一&#xff0c;搭建基本框架 1. 利用linux第三方库&#xff0c;将pthread_creat线程接口封装 2. 实现基本主类ThreadPool基本结构 阶段二&#xff0c;完善多线程安全 1. 日志信息打印…

Go数据结构的底层原理(图文详解)

空结构体的底层原理 基本类型的字节数 fmt.Println(unsafe.Sizeof(0)) // 8 fmt.Println(unsafe.Sizeof(uint(0))) // 8 a : 0 b : &a fmt.Println(unsafe.Sizeof(b)) // 8int大小跟随系统字长指针的大小也是系统字长 空结构体 a : struct { }{} b : struct {…

jdk目录结构

jdk目录详解 JDK(Java Development Kit&#xff0c;Java开发包&#xff0c;Java开发工具)是一个写Java的applet和应用程序的程序开发环境。它由一个处于操作系统层之上的运行环境还有开发者 编译&#xff0c;调试和运行用Java语言写的applet和应用程序所需的工具组成。 JDK(J…

京东云轻量云主机8核16G配置租用价格1198元1年、4688元三年

京东云轻量云主机8核16G服务器租用优惠价格1198元1年、4688元三年&#xff0c;配置为8C16G-270G SSD系统盘-5M带宽-500G月流量&#xff0c;华北-北京地域。京东云8核16G服务器活动页面 yunfuwuqiba.com/go/jd 活动链接打开如下图&#xff1a; 京东云8核16G服务器优惠价格 京东云…

C语言基础语法-教案19(预处理-宏定义)

最近给大家争取到一个 深夜福利 保证你在深夜手机刷到 嘎嘎香~ 那就是 官方授权 大流量卡 缺点&#xff1a;月租太便宜 185GB~ 100分钟通话时长~ 长期套餐~ 畅想自由的气息 流量自由的同时还拥有超长通话&#xff0c;而且免费领取。 名额有限&#xff0c;咱们废话不…

流程表单平台优势明显,助力企业流程化办公!

要想提升办公效率&#xff0c;实现流程化办公&#xff0c;可以了解低代码技术平台、流程表单平台的应用价值和优势特点。在科技越来越发达和先进的今天&#xff0c;采用专业的平台和软件可以为企业带来超前的发展态势&#xff0c;创造更多市场价值。流辰信息为广大用户提供的流…

闲鱼订阅监控/上新提醒

以前闲鱼推出过一款服务&#xff0c;叫做闲鱼助手&#xff0c;帮助用户快速显示最新发布的信息。当时我也开发过一款闲鱼助手的工具。 写一个闲鱼助手的助手工具_闲鱼助手源码-CSDN博客 但是时间并不是很长&#xff0c;该功能被取消了。 最近不知道闲鱼从哪个版本开始&#x…

数字三角形(线性dp)-java

线性DP是动态规划问题中的一类问题&#xff0c;指状态之间有线性关系的动态规划问题。 文章目录 前言 一、数字三角形问题 二、算法思路 三、使用步骤 1.代码如下&#xff08;示例&#xff09;&#xff1a; 2.读入数据 3.代码运行结果 总结 前言 线性DP是动态规划问题中的一类…

工业和信息化部教育与考试中心颁发的证书有哪些?含金量如何?怎么考取?​

近期有很多网友朋友们对工业和信息化部教育与考试中心颁发的证书是否是真的证书&#xff0c;是否国家认可&#xff0c;是否全国通用&#xff0c;含金量如何&#xff1f;如何查询真假&#xff0c;以及如何报考等等相关问题有疑问&#xff0c;所以今天给大家在这里一一解答。 添加…

2.AK/SK鉴权

目录 什么是AK/SK AK/SK使用机制 时序图 什么是AK/SK 在云服务中&#xff0c;AK&#xff08;Access Key ID&#xff09;和SK&#xff08;Secret Access Key&#xff09;是访问云服务API的关键凭证对&#xff0c;主要用于身份验证和授权。AK是用户访问云服务的身份标识&…