RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

鴻蒙內(nèi)核源碼分析之任何管理多個(gè)CPU?

鴻蒙系統(tǒng)HarmonyOS ? 來源:my.oschina ? 作者:鴻蒙內(nèi)核源碼分析 ? 2021-04-25 09:24 ? 次閱讀

并發(fā)(Concurrent):多個(gè)線程在單個(gè)核心運(yùn)行,同一時(shí)間只能一個(gè)線程運(yùn)行,內(nèi)核不停切換線程,看起來像同時(shí)運(yùn)行,實(shí)際上是線程被高速的切換.

通俗好理解的比喻就是高速單行道,單行道指的是CPU的核數(shù),跑的車就是線程(任務(wù)),進(jìn)程就是管理車的公司,一個(gè)公司可以有很多臺(tái)車.并發(fā)和并行跟CPU的核數(shù)有關(guān).車道上同時(shí)只能跑一輛車,但因?yàn)橹笓]系統(tǒng)很牛,夠快,在毫秒級(jí)內(nèi)就能換車跑,人根本感知不到切換.所以外部的感知會(huì)是同時(shí)在進(jìn)行,實(shí)現(xiàn)了微觀上的串行,宏觀上的并行.

線程切換的本質(zhì)是CPU要換場地上班,去哪里上班由哪里提供場地,那個(gè)場地就是任務(wù)棧,每個(gè)任務(wù)棧中保存了上班的各種材料,來了就行立馬干活.那些材料就是任務(wù)上下文.簡單的說就是上次活干到那里了,回來繼續(xù)接著干.上下文由任務(wù)棧自己保存,CPU不管的,它來了只負(fù)責(zé)任務(wù)交過來的材料,材料顯示去哪里搬磚它就去哪里搬磚.

記住一個(gè)單詞就能記住并行并發(fā)的區(qū)別, 發(fā)單,發(fā)單(并發(fā)單行).

理解并行概念

并行(Parallel)每個(gè)線程分配給獨(dú)立的CPU核心,線程真正的同時(shí)運(yùn)行.

通俗好理解的比喻就是高速多行道,實(shí)現(xiàn)了微觀和宏觀上同時(shí)進(jìn)行. 并行當(dāng)然是快,人多了干活就不那么累,但干活人多了必然會(huì)帶來人多的管理問題,會(huì)把問題變復(fù)雜,請(qǐng)想想會(huì)出現(xiàn)哪些問題?

理解協(xié)程概念

這里說下協(xié)程,例如go語言是有協(xié)程支持的,其實(shí)協(xié)程跟內(nèi)核層沒有關(guān)系,是應(yīng)用層的概念.是在線程之上更高層的封裝,用通俗的比喻來說就是在車內(nèi)另外搞了幾條車道玩.其對(duì)內(nèi)核來說沒有新東西,內(nèi)核只負(fù)責(zé)車的調(diào)度,至于車內(nèi)你想怎么弄那是應(yīng)用程序自己的事.本質(zhì)的區(qū)別是CPU根本沒有換地方上班(沒有被調(diào)度),而并發(fā)/并行都是換地方上班了.

內(nèi)核如何描述CPU

    typedef struct {
        SortLinkAttribute taskSortLink;             /* task sort link */ //每個(gè)CPU core 都有一個(gè)task排序鏈表
        SortLinkAttribute swtmrSortLink;            /* swtmr sort link */ //每個(gè)CPU core 都有一個(gè)定時(shí)器排序鏈表

        UINT32 idleTaskID;                          /* idle task id */  //空閑任務(wù)ID 見于 OsIdleTaskCreate
        UINT32 taskLockCnt;                         /* task lock flag */ //任務(wù)鎖的數(shù)量,當(dāng) > 0 的時(shí)候,需要重新調(diào)度了
        UINT32 swtmrHandlerQueue;                   /* software timer timeout queue id */ //軟時(shí)鐘超時(shí)隊(duì)列句柄
        UINT32 swtmrTaskID;                         /* software timer task id */ //軟時(shí)鐘任務(wù)ID

        UINT32 schedFlag;                           /* pending scheduler flag */ //調(diào)度標(biāo)識(shí) INT_NO_RESCH INT_PEND_RESCH
    #if (LOSCFG_KERNEL_SMP == YES)
        UINT32 excFlag;                             /* cpu halt or exc flag */ //CPU處于停止或運(yùn)行的標(biāo)識(shí)
    #endif
    } Percpu;

    Percpu g_percpu[LOSCFG_KERNEL_CORE_NUM];//全局CPU數(shù)組

這是內(nèi)核對(duì)CPU的描述,主要是兩個(gè)排序鏈表,一個(gè)是任務(wù)的排序,一個(gè)是定時(shí)器的排序.什么意思? 在系列篇中多次提過,任務(wù)是內(nèi)核的調(diào)度單元,注意可不是進(jìn)程,雖然調(diào)度也需要進(jìn)程參與,也需要切換進(jìn)程,切換用戶空間.但調(diào)度的核心是切換任務(wù),每個(gè)任務(wù)的代碼指令才是CPU的糧食,它吃的是一條條的指令.每個(gè)任務(wù)都必須指定取糧地址(即入口函數(shù)).

另外還有一個(gè)東西能提供入口函數(shù),就是定時(shí)任務(wù).很重要也很常用,沒它某寶每晚9點(diǎn)的準(zhǔn)時(shí)秒殺實(shí)現(xiàn)不了.在內(nèi)核每個(gè)CPU都有自己獨(dú)立的任務(wù)和定時(shí)器鏈表.

每次Tick的到來,處理函數(shù)會(huì)去掃描這兩個(gè)鏈表,看有沒有定時(shí)器超時(shí)的任務(wù)需要執(zhí)行,有則立即執(zhí)行定時(shí)任務(wù),定時(shí)任務(wù)是所有任務(wù)中優(yōu)先級(jí)最高的,0號(hào)優(yōu)先級(jí),在系列篇中有專門講定時(shí)器任務(wù),可自行翻看.

LOSCFG_KERNEL_SMP

# if (LOSCFG_KERNEL_SMP == YES)
# define LOSCFG_KERNEL_CORE_NUM                          LOSCFG_KERNEL_SMP_CORE_NUM //多核情況下支持的CPU核數(shù)
# else
# define LOSCFG_KERNEL_CORE_NUM                          1 //單核配置
# endif

多CPU核的操作系統(tǒng)有3種處理模式(SMP+AMP+BMP) 鴻蒙實(shí)現(xiàn)的是 SMP 的方式

非對(duì)稱多處理(Asymmetric multiprocessing,AMP)每個(gè)CPU內(nèi)核運(yùn)行一個(gè)獨(dú)立的操作系統(tǒng)或同一操作系統(tǒng)的獨(dú)立實(shí)例(instantiation)。

對(duì)稱多處理(Symmetric multiprocessing,SMP)一個(gè)操作系統(tǒng)的實(shí)例可以同時(shí)管理所有CPU內(nèi)核,且應(yīng)用并不綁定某一個(gè)內(nèi)核。

混合多處理(Bound multiprocessing,BMP)一個(gè)操作系統(tǒng)的實(shí)例可以同時(shí)管理所有CPU內(nèi)核,但每個(gè)應(yīng)用被鎖定于某個(gè)指定的核心。

宏LOSCFG_KERNEL_SMP表示對(duì)多CPU核的支持,鴻蒙默認(rèn)是打開LOSCFG_KERNEL_SMP的。

多CPU核支持

鴻蒙內(nèi)核對(duì)CPU的操作見于 los_mp.c ,因文件不大,這里把代碼都貼出來了.

    #if (LOSCFG_KERNEL_SMP == YES)
    //給參數(shù)CPU發(fā)送調(diào)度信號(hào)
    VOID LOS_MpSchedule(UINT32 target)//target每位對(duì)應(yīng)CPU core 
    {
        UINT32 cpuid = ArchCurrCpuid();
        target &= ~(1U << cpuid);//獲取除了自身之外的其他CPU
        HalIrqSendIpi(target, LOS_MP_IPI_SCHEDULE);//向目標(biāo)CPU發(fā)送調(diào)度信號(hào),核間中斷(Inter-Processor Interrupts),IPI
    }
    //硬中斷喚醒處理函數(shù)
    VOID OsMpWakeHandler(VOID)
    {
        /* generic wakeup ipi, do nothing */
    }
    //硬中斷調(diào)度處理函數(shù)
    VOID OsMpScheduleHandler(VOID)
    {//將調(diào)度標(biāo)志設(shè)置為與喚醒功能不同,這樣就可以在硬中斷結(jié)束時(shí)觸發(fā)調(diào)度程序。
        /*
        * 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;//給當(dāng)前Cpu貼上調(diào)度標(biāo)簽
    }
    //硬中斷暫停處理函數(shù)
    VOID OsMpHaltHandler(VOID)
    {
        (VOID)LOS_IntLock();
        OsPercpuGet()->excFlag = CPU_HALT;//讓當(dāng)前Cpu停止工作

        while (1) {}//陷入空循環(huán),也就是空閑狀態(tài)
    }
    //MP定時(shí)器處理函數(shù), 遞歸檢查所有可用任務(wù)
    VOID OsMpCollectTasks(VOID)
    {
        LosTaskCB *taskCB = NULL;
        UINT32 taskID = 0;
        UINT32 ret;

        /* recursive checking all the available task */
        for (; taskID <= g_taskMaxNum; taskID++) { //遞歸檢查所有可用任務(wù)
            taskCB = &g_taskCBArray[taskID];

            if (OsTaskIsUnused(taskCB) || OsTaskIsRunning(taskCB)) {
                continue;
            }

            /* 雖然任務(wù)狀態(tài)不是原子的,但此檢查可能成功,但無法完成刪除,此刪除將在下次運(yùn)行之前處理
            * 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) {//任務(wù)收到被干掉信號(hào)
                ret = LOS_TaskDelete(taskID);//干掉任務(wù),回歸任務(wù)池
                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, //創(chuàng)建一個(gè)周期性,持續(xù)時(shí)間為 100個(gè)tick的定時(shí)器
                            (SWTMR_PROC_FUNC)OsMpCollectTasks, &swtmrId, 0);//OsMpCollectTasks為超時(shí)回調(diào)函數(shù)
        (VOID)LOS_SwtmrStart(swtmrId);//開始定時(shí)任務(wù)

        return LOS_OK;
    }
    #endif

代碼一一都加上了注解,這里再一一說明下:

1.OsMpInit

多CPU核的初始化, 多核情況下每個(gè)CPU都有各自的編號(hào), 內(nèi)核有分成主次CPU, 0號(hào)默認(rèn)為主CPU, OsMain()由主CPU執(zhí)行,被匯編代碼調(diào)用. 初始化只開了個(gè)定時(shí)任務(wù),只干一件事就是回收不用的任務(wù).回收的條件是任務(wù)是否收到了被干掉的信號(hào). 例如shell命令 kill 9 14 ,意思是干掉14號(hào)線程的信號(hào),這個(gè)信號(hào)會(huì)被線程保存起來. 可以選擇自殺也可以等著被殺. 這里要注意,鴻蒙有兩種情況下任務(wù)不能被干掉, 一種是系統(tǒng)任務(wù)不能被干掉的, 第二種是正在運(yùn)行狀態(tài)的任務(wù).

2.次級(jí)CPU的初始化

同樣由匯編代碼調(diào)用,通過以下函數(shù)執(zhí)行,完成每個(gè)CPU核的初始化

    //次級(jí)CPU初始化,本函數(shù)執(zhí)行的次數(shù)由次級(jí)CPU的個(gè)數(shù)決定. 例如:在四核情況下,會(huì)被執(zhí)行3次, 0號(hào)通常被定義為主CPU 執(zhí)行main
    LITE_OS_SEC_TEXT_INIT VOID secondary_cpu_start(VOID)
    {
    #if (LOSCFG_KERNEL_SMP == YES)
        UINT32 cpuid = ArchCurrCpuid();

        OsArchMmuInitPerCPU();//每個(gè)CPU都需要初始化MMU

        OsCurrTaskSet(OsGetMainTask());//設(shè)置CPU的當(dāng)前任務(wù)

        /* increase cpu counter */
        LOS_AtomicInc(&g_ncpu); //統(tǒng)計(jì)CPU的數(shù)量

        /* store each core's hwid */
        CPU_MAP_SET(cpuid, OsHwIDGet());//存儲(chǔ)每個(gè)CPU的 hwid
        HalIrqInitPercpu(); //CPU硬件中斷初始化

        OsCurrProcessSet(OS_PCB_FROM_PID(OsGetKernelInitProcessID())); //設(shè)置內(nèi)核進(jìn)程為CPU進(jìn)程
        OsSwtmrInit();  //定時(shí)任務(wù)初始化,每個(gè)CPU維護(hù)自己的定時(shí)器隊(duì)列
        OsIdleTaskCreate(); //創(chuàng)建空閑任務(wù),每個(gè)CPU維護(hù)自己的任務(wù)隊(duì)列
        OsStart(); //本CPU正式啟動(dòng)在內(nèi)核層的工作
        while (1) {
            __asm volatile("wfi");//wait for Interrupt 等待中斷,即下一次中斷發(fā)生前都在此hold住不干活
        }//類似的還有 WFE: wait for Events 等待事件,即下一次事件發(fā)生前都在此hold住不干活
    #endif
    }

可以看出次級(jí)CPU有哪些初始化步驟:

初始化MMU,OsArchMmuInitPerCPU

設(shè)置當(dāng)前任務(wù) OsCurrTaskSet

初始化硬件中斷 HalIrqInitPercpu

初始化定時(shí)器隊(duì)列 OsSwtmrInit

創(chuàng)建空任務(wù) OsIdleTaskCreate, 外面沒有任務(wù)的時(shí)CPU就待在這個(gè)空任務(wù)里自己轉(zhuǎn)圈圈.

開始自己的工作流程 OsStart,正式開始工作,跑任務(wù)

多CPU核還有哪些問題?

CPU之間搶資源的情況要怎么處理?

CPU之間通訊(也叫核間通訊)怎么解決?

如果確保兩個(gè)CPU不會(huì)同時(shí)執(zhí)行同一個(gè)任務(wù)?

匯編代碼如何實(shí)現(xiàn)對(duì)各CPU的調(diào)動(dòng)

請(qǐng)前往系列篇或直接前往內(nèi)核注解代碼查看.這里不再做說明.

編輯:hfy

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10854

    瀏覽量

    211574
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    504

    瀏覽量

    19675
  • 鴻蒙系統(tǒng)
    +關(guān)注

    關(guān)注

    183

    文章

    2634

    瀏覽量

    66302
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    鴻蒙內(nèi)核源碼Task/線程技術(shù)分析

    前言 在鴻蒙內(nèi)核中,廣義上可理解為一個(gè)Task就是一個(gè)線程 一、怎么理解Task 1. 官方文檔是怎么描述線程 基本概念 從系統(tǒng)的角度看,線程是競爭系統(tǒng)資源的最小運(yùn)行單元。線程可以使用或等待CPU
    的頭像 發(fā)表于 10-18 10:42 ?2207次閱讀
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b>Task/線程技術(shù)<b class='flag-5'>分析</b>

    【HarmonyOS】鴻蒙內(nèi)核源碼分析(調(diào)度機(jī)制篇)

    CPU的層面,它只認(rèn)任務(wù)上下文!這里看不到任何代碼了,因?yàn)檫@是跟CPU相關(guān)的,不同的CPU需要去適配不同的匯編代碼,所以這些匯編代碼不會(huì)出現(xiàn)在一個(gè)通用工程中。請(qǐng)留意后續(xù)
    發(fā)表于 10-14 14:00

    鴻蒙內(nèi)核源碼分析:用通俗易懂的語言告訴你鴻蒙內(nèi)核發(fā)生了什么?

    是:鴻蒙內(nèi)核源碼分析(內(nèi)存概念篇)| 鴻蒙內(nèi)核源碼
    發(fā)表于 11-19 10:14

    鴻蒙內(nèi)核源碼分析源碼注釋篇):給HarmonyOS源碼逐行加上中文注釋

    都懂的概念去詮釋或者映射一個(gè)他們從沒聽過的概念.說別人能聽得懂的話這很重要!!! 一個(gè)沒學(xué)過計(jì)算機(jī)知識(shí)的賣菜大媽就不可能知道內(nèi)核的基本運(yùn)作了嗎? NO!,筆者在系列篇中試圖用 鴻蒙源碼分析
    發(fā)表于 11-19 10:32

    鴻蒙源碼分析系列(總目錄) | 給HarmonyOS源碼逐行加上中文注釋

    同步更新。鴻蒙源碼分析系列篇|- 鴻蒙內(nèi)核源碼分析
    發(fā)表于 11-20 11:24

    鴻蒙內(nèi)核源碼分析(內(nèi)存概念篇) :手眼通天的虛擬內(nèi)存

    分析(內(nèi)存管理篇) | 鴻蒙內(nèi)核源碼分析(內(nèi)存匯編篇) |
    發(fā)表于 11-20 13:52

    鴻蒙內(nèi)核源碼分析(內(nèi)存概念篇) :手眼通天的虛擬內(nèi)存

    管理篇) | 鴻蒙內(nèi)核源碼分析(內(nèi)存匯編篇) |鴻蒙內(nèi)核
    發(fā)表于 11-20 16:30

    鴻蒙內(nèi)核源碼分析(必讀篇):用故事說內(nèi)核

    的工作原理!操作系統(tǒng)就是管理場館和確保工作人員有序工作的系統(tǒng)解決方案商,外面公司只要提供個(gè)節(jié)目單,就能按節(jié)目單把這臺(tái)戲演好給廣大觀眾觀看。有了這個(gè)故事墊底,鴻蒙內(nèi)核源碼
    發(fā)表于 11-23 10:15

    鴻蒙內(nèi)核源碼分析(調(diào)度機(jī)制篇):Task是如何被調(diào)度執(zhí)行的

    認(rèn)任務(wù)上下文!這里看不到任何代碼了,因?yàn)檫@是跟CPU相關(guān)的,不同的CPU需要去適配不同的匯編代碼,所以這些匯編代碼不會(huì)出現(xiàn)在一個(gè)通用工程中。請(qǐng)留意后續(xù) 鴻蒙
    發(fā)表于 11-23 10:53

    鴻蒙內(nèi)核源碼分析(必讀篇)

    的工作原理!操作系統(tǒng)就是管理場館和確保工作人員有序工作的系統(tǒng)解決方案商,外面公司只要提供個(gè)節(jié)目單,就能按節(jié)目單把這臺(tái)戲演好給廣大觀眾觀看。有了這個(gè)故事墊底,鴻蒙內(nèi)核源碼
    發(fā)表于 11-25 09:28

    鴻蒙內(nèi)核源碼分析鴻蒙內(nèi)核的每段匯編代碼解析

    本篇說清楚CPU的工作模式 讀本篇之前建議先讀鴻蒙內(nèi)核源碼分析(總目錄)其他篇. 正如一個(gè)互聯(lián)網(wǎng)項(xiàng)目的后臺(tái)
    的頭像 發(fā)表于 03-02 09:56 ?4340次閱讀
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b>:<b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b>的每段匯編代碼解析

    鴻蒙內(nèi)核源碼分析: 虛擬內(nèi)存和物理內(nèi)存是怎么管理

    有了上篇鴻蒙內(nèi)核源碼分析(內(nèi)存概念篇)的基礎(chǔ),本篇講內(nèi)存管理部分,本章源碼超級(jí)多,很燒腦,但筆者
    發(fā)表于 11-23 11:45 ?19次下載
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b>: 虛擬內(nèi)存和物理內(nèi)存是怎么<b class='flag-5'>管理</b>的

    鴻蒙內(nèi)核源碼分析:進(jìn)程是內(nèi)核的資源管理單元

    從系統(tǒng)的角度看,進(jìn)程是資源管理單元。進(jìn)程可以使用或等待CPU、使用內(nèi)存空間等系統(tǒng)資源,并獨(dú)立于其它進(jìn)程運(yùn)行。OpenHarmony內(nèi)核的進(jìn)程模塊可以給用戶提供多個(gè)進(jìn)程,實(shí)現(xiàn)了進(jìn)程之間的
    發(fā)表于 11-24 17:52 ?23次下載
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b>:進(jìn)程是<b class='flag-5'>內(nèi)核</b>的資源<b class='flag-5'>管理</b>單元

    鴻蒙內(nèi)核源碼分析內(nèi)核最重要結(jié)構(gòu)體

    為何鴻蒙內(nèi)核源碼分析系列開篇就說 LOS_DL_LIST ? 因?yàn)樗?b class='flag-5'>鴻蒙 LOS 內(nèi)核中無處
    發(fā)表于 11-24 17:54 ?35次下載
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b> :<b class='flag-5'>內(nèi)核</b>最重要結(jié)構(gòu)體

    華為鴻蒙系統(tǒng)內(nèi)核源碼分析上冊(cè)

    鴻蒙內(nèi)核源碼注釋中文版【 Gitee倉】給 Harmoηy○S源碼逐行加上中文注解,詳細(xì)闡述設(shè)計(jì)細(xì)節(jié),助你快速精讀 Harmonyos內(nèi)核源碼
    發(fā)表于 04-09 14:40 ?17次下載
    RM新时代网站-首页