国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
讀了鴻蒙 OS 的代碼后,我發(fā)現(xiàn)優(yōu)秀項(xiàng)目都有這個(gè)共性!

最近有人在Github上開源了鴻蒙OS(https://www.github.com/Awesome-HarmonyOS)并且累計(jì)獲得了一萬(wàn)多顆Star。
從華為的官方宣傳中就提到了“安卓總代碼超過(guò)一億行,其中內(nèi)核代碼超過(guò)2000萬(wàn)行,實(shí)際用到的不過(guò)8%,如此龐大和冗余的這種設(shè)計(jì),實(shí)際上很難保證流暢度,使用效率很低?!?nbsp;
而筆者之前介紹過(guò)的TDengine(https://github.com/taosdata/TDengine)做為一個(gè)數(shù)據(jù)庫(kù)項(xiàng)目更是僅用1.5M安裝包就能搞定,代碼效率高的驚人。
所以從這方面我們也能看出優(yōu)秀的項(xiàng)目對(duì)于速度的要求都是極致的。
不過(guò)這兩個(gè)項(xiàng)目開源后都引發(fā)了一些爭(zhēng)議,比如鴻蒙開源當(dāng)天就有人發(fā)微博說(shuō)華為只是做了個(gè)安卓的定制版,質(zhì)量甚至還不如MIUI,筆者的這位創(chuàng)造Github冠軍項(xiàng)目的老男人,堪稱10倍程序員本尊發(fā)布后,也有人在評(píng)論說(shuō)TDengine的consumer-productor實(shí)現(xiàn)無(wú)法通過(guò)code review。
但是仔細(xì)閱讀這些評(píng)論可以發(fā)現(xiàn),這些批評(píng)其實(shí)都不是基于代碼的。筆者做為一名程序員奉行“Talk is cheap,show me the code'的理念,所以我利用周末時(shí)間閱讀了這兩個(gè)項(xiàng)目的代碼,發(fā)現(xiàn)了很多值得學(xué)習(xí)的設(shè)計(jì)亮點(diǎn)。
尤其是鴻蒙OS做為操作系統(tǒng)項(xiàng)目而Tdengine做為數(shù)據(jù)庫(kù)項(xiàng)目,比較他們兩者在同一模塊上的設(shè)計(jì)異同,非常有收獲,下面給各位讀者分享一下,如有意見(jiàn)歡迎留言。

兩個(gè)項(xiàng)目對(duì)于任務(wù)調(diào)度模塊的實(shí)現(xiàn)對(duì)比

1.鴻蒙OS的調(diào)度模塊
與一般操作系統(tǒng)一樣,鴻蒙也將任務(wù)狀態(tài)通常分為以下三種:
  • 就緒(Ready):

    該任務(wù)在就緒列表中,只等待CPU。

  • 運(yùn)行(Running):

    該任務(wù)正在執(zhí)行。

  • 阻塞(Blocked):

    該任務(wù)不在就緒列表中。

    包含任務(wù)被掛起、任務(wù)被延時(shí)、任務(wù)正在等待信號(hào)量、讀寫隊(duì)列或者等待讀寫事件等。

任務(wù)狀態(tài)遷移圖
其代碼位置在los_task.c,以任務(wù)恢復(fù)函數(shù)LOS_TaskResume為例,其代碼如下:
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskResume(UINT32 uwTaskID)
{
    UINTPTR uvIntSave;
    LOS_TASK_CB *pstTaskCB;
    UINT16 usTempStatus;
    UINT32 uwErrRet = OS_ERROR;

    if (uwTaskID > LOSCFG_BASE_CORE_TSK_LIMIT)
    {
        return LOS_ERRNO_TSK_ID_INVALID;
    }

    pstTaskCB = OS_TCB_FROM_TID(uwTaskID);
    uvIntSave = LOS_IntLock();
    usTempStatus = pstTaskCB->usTaskStatus;

    if (OS_TASK_STATUS_UNUSED & usTempStatus)
    {
        uwErrRet = LOS_ERRNO_TSK_NOT_CREATED;
        OS_GOTO_ERREND();
    }
    else if (!(OS_TASK_STATUS_SUSPEND & usTempStatus))
    {
        uwErrRet = LOS_ERRNO_TSK_NOT_SUSPENDED;
        OS_GOTO_ERREND();
    }
    //以上為任務(wù)狀態(tài)檢查
    pstTaskCB->usTaskStatus &= (~OS_TASK_STATUS_SUSPEND);//清除任務(wù)的suspend標(biāo)志位置
    if (!(OS_CHECK_TASK_BLOCK & pstTaskCB->usTaskStatus) )//若任務(wù)的還自在阻塞狀態(tài)則變?yōu)榫途w狀態(tài) ,并調(diào)用 LOS_Schedule()進(jìn)行調(diào)度
    {
        pstTaskCB->usTaskStatus |= OS_TASK_STATUS_READY;
        LOS_PriqueueEnqueue(&pstTaskCB->stPendList, pstTaskCB->usPriority);
        if (g_bTaskScheduled)
        {
            (VOID)LOS_IntRestore(uvIntSave);
            LOS_Schedule();
            return LOS_OK;
        }
        g_stLosTask.pstNewTask = LOS_DL_LIST_ENTRY(LOS_PriqueueTop(), LOS_TASK_CB, stPendList); /*lint !e413*/
    }

    (VOID)LOS_IntRestore(uvIntSave);
    return LOS_OK;

LOS_ERREND:
    (VOID)LOS_IntRestore(uvIntSave);
    return uwErrRet;
}
 我們看到這個(gè)函數(shù)的處理過(guò)程基本分為三步:
  • 任務(wù)合法性(TaskId)及任務(wù)狀態(tài)校驗(yàn):判斷任務(wù)序號(hào)以及任務(wù)當(dāng)前狀態(tài)是否確實(shí)為掛起。

  • 改變?nèi)蝿?wù)狀態(tài):將任務(wù)的suspend狀態(tài)位清掉

  • 起用任務(wù)調(diào)度:如果任務(wù)被阻塞,則調(diào)起LOS_Schedule進(jìn)行調(diào)度。

我們知道完整的LINUX內(nèi)核是支持將任務(wù)指定在某個(gè)CPU上運(yùn)行的,不過(guò)鴻蒙OS做為一個(gè)微內(nèi)核的移動(dòng)操作系統(tǒng)沒(méi)有繼承這些復(fù)雜的功能,直接做了減法,實(shí)現(xiàn)一個(gè)最簡(jiǎn)模型。
2.TdEngine的任務(wù)調(diào)度模塊    
而對(duì)比TDengine的調(diào)度模塊tsched.c,可以看到TDengine更是放棄了任務(wù)優(yōu)先級(jí)調(diào)度功能,因?yàn)樽鰹闀r(shí)序數(shù)據(jù)庫(kù)其數(shù)據(jù)全是按照生成時(shí)間排序處理入庫(kù)的,所以他的只將任務(wù)調(diào)度模塊,僅實(shí)現(xiàn)了以下四個(gè)功能
  • 初始化任務(wù)隊(duì)列

  • 加入任務(wù)

  • 循環(huán)處理任務(wù)

  • 銷毀任務(wù)隊(duì)列

從其循環(huán)處理任務(wù)的函數(shù)(taosProcessSchedQueue),可以看出它只是隊(duì)尾不斷取出任務(wù)進(jìn)行循環(huán)處理,而沒(méi)有優(yōu)化級(jí)調(diào)整排序的過(guò)程。
void *taosProcessSchedQueue(void *param) {
  SSchedMsg    msg;
  SSchedQueue *pSched = (SSchedQueue *)param;

  while (1) {
    if (sem_wait(&pSched->fullSem) != 0) {
      pError('wait %s fullSem failed, errno:%d, reason:%s', pSched->label, errno, strerror(errno));
      if (errno == EINTR) {
        /* sem_wait is interrupted by interrupt, ignore and continue */
        continue;
      }
    }

    if (pthread_mutex_lock(&pSched->queueMutex) != 0)
      pError('lock %s queueMutex failed, reason:%s', pSched->label, strerror(errno));

    msg = pSched->queue[pSched->fullSlot];
    memset(pSched->queue   pSched->fullSlot, 0, sizeof(SSchedMsg));
    pSched->fullSlot = (pSched->fullSlot   1) % pSched->queueSize;//從隊(duì)尾取出消息不斷處理

    if (pthread_mutex_unlock(&pSched->queueMutex) != 0)
      pError('unlock %s queueMutex failed, reason:%s
', pSched->label, strerror(errno));

    if (sem_post(&pSched->emptySem) != 0)
      pError('post %s emptySem failed, reason:%s
', pSched->label, strerror(errno));

    if (msg.fp)
      (*(msg.fp))(&msg);
    else if (msg.tfp)
      (*(msg.tfp))(msg.ahandle, msg.thandle);
  }
}

int taosScheduleTask(void *qhandle, SSchedMsg *pMsg) {
  SSchedQueue *pSched = (SSchedQueue *)qhandle;
  if (pSched == NULL) {
    pError('sched is not ready, msg:%p is dropped', pMsg);
    return 0;
  }

  if (sem_wait(&pSched->emptySem) != 0) pError('wait %s emptySem failed, reason:%s', pSched->label, strerror(errno));

  if (pthread_mutex_lock(&pSched->queueMutex) != 0)
    pError('lock %s queueMutex failed, reason:%s', pSched->label, strerror(errno));

  pSched->queue[pSched->emptySlot] = *pMsg;
  pSched->emptySlot = (pSched->emptySlot   1) % pSched->queueSize;

  if (pthread_mutex_unlock(&pSched->queueMutex) != 0)
    pError('unlock %s queueMutex failed, reason:%s', pSched->label, strerror(errno));

  if (sem_post(&pSched->fullSem) != 0) pError('post %s fullSem failed, reason:%s', pSched->label, strerror(errno));

  return 0;
}
  
  兩個(gè)項(xiàng)目對(duì)于定時(shí)器(timer)的實(shí)現(xiàn)對(duì)比

1.鴻蒙的timer
在鴻蒙的官方文檔中是這么介紹定時(shí)器的:
軟件定時(shí)器,是基于系統(tǒng)Tick時(shí)鐘中斷且由軟件來(lái)模擬的定時(shí)器,當(dāng)經(jīng)過(guò)設(shè)定的Tick時(shí)鐘計(jì)數(shù)值后會(huì)觸發(fā)用戶定義的回調(diào)函數(shù)。定時(shí)精度與系統(tǒng)Tick時(shí)鐘的周期有關(guān)。 
硬件定時(shí)器受硬件的限制,數(shù)量上不足以滿足用戶的實(shí)際需求,因此為了滿足用戶需求,提供更多的定時(shí)器,Huawei LiteOS操作系統(tǒng)提供軟件定時(shí)器功能。軟件定時(shí)器擴(kuò)展了定時(shí)器的數(shù)量,允許創(chuàng)建更多的定時(shí)業(yè)務(wù)。
2.運(yùn)作機(jī)制
  • 軟件定時(shí)器是系統(tǒng)資源,在模塊初始化的時(shí)候已經(jīng)分配了一塊連續(xù)的內(nèi)存,系統(tǒng)支持的最大定時(shí)器個(gè)數(shù)可以在los_config.h文件中配置。

  • 軟件定時(shí)器使用了系統(tǒng)的一個(gè)隊(duì)列和任務(wù)資源,軟件定時(shí)器的觸發(fā)遵循隊(duì)列規(guī)則,先進(jìn)先出。

    定時(shí)時(shí)間短的定時(shí)器總是比定時(shí)時(shí)間長(zhǎng)的靠近隊(duì)列頭,滿足優(yōu)先被觸發(fā)的準(zhǔn)則。

  • 軟件定時(shí)器以Tick為基本計(jì)時(shí)單位,當(dāng)用戶創(chuàng)建并啟動(dòng)一個(gè)軟件定時(shí)器時(shí),Huawei LiteOS會(huì)根據(jù)當(dāng)前系統(tǒng)Tick時(shí)間及用戶設(shè)置的定時(shí)間隔確定該定時(shí)器的到期Tick時(shí)間,并將該定時(shí)器控制結(jié)構(gòu)掛入計(jì)時(shí)全局鏈表。

  • 當(dāng)Tick中斷到來(lái)時(shí),在Tick中斷處理函數(shù)中掃描軟件定時(shí)器的計(jì)時(shí)全局鏈表,看是否有定時(shí)器超時(shí),若有則將超時(shí)的定時(shí)器記錄下來(lái)。

  • Tick處理結(jié)束后,軟件定時(shí)器任務(wù)(優(yōu)先級(jí)為最高)被喚醒,在該任務(wù)中調(diào)用之前記錄下來(lái)的超時(shí)定時(shí)器的處理函數(shù)。

3.代碼解讀
如果官方文檔的說(shuō)明沒(méi)看懂,可以直接查閱其源代碼,具體位置在los_swtmr.c
下面筆者來(lái)簡(jiǎn)述一下鴻蒙定時(shí)器的工作原理。
  • 首先明確鴻蒙的定時(shí)器是為了節(jié)省硬件定時(shí)器資源而設(shè)計(jì)的。

    由于硬件定時(shí)器往往數(shù)量有限而系統(tǒng)實(shí)際運(yùn)行中,對(duì)于定時(shí)器的需求往往高于硬件定時(shí)器的數(shù)量,所以操作系統(tǒng)都會(huì)實(shí)現(xiàn)軟件定時(shí)器以滿足用戶需求。

  • 先啟動(dòng)硬件定時(shí)器,注冊(cè)硬件定時(shí)器的tick事件,也就是硬件定時(shí)器到時(shí)發(fā)生tick時(shí)會(huì)調(diào)用軟件定時(shí)器的處理函數(shù)。

  • 將在同一時(shí)刻到期的timer放在同一鏈表中。

  • 在硬件產(chǎn)生tick事件時(shí),取出當(dāng)時(shí)到期的定時(shí)器列表,并順序調(diào)起鏈表內(nèi)所有到時(shí)定時(shí)器的處理函數(shù)。

LITE_OS_SEC_TEXT VOID osSwTmrTask(VOID)
{
    SWTMR_HANDLER_ITEM_P pstSwtmrHandle = (SWTMR_HANDLER_ITEM_P)NULL;
    SWTMR_HANDLER_ITEM_S stSwtmrHandle;
    UINT32 uwRet;

    for ( ; ; )
    {
        uwRet = LOS_QueueRead(m_uwSwTmrHandlerQueue, &pstSwtmrHandle, sizeof(SWTMR_HANDLER_ITEM_P), LOS_WAIT_FOREVER);
        if (uwRet == LOS_OK)
        {
            if (pstSwtmrHandle != NULL)
            {
                stSwtmrHandle.pfnHandler = pstSwtmrHandle->pfnHandler;
                stSwtmrHandle.uwArg = pstSwtmrHandle->uwArg;
                (VOID)LOS_MemboxFree(m_aucSwTmrHandlerPool, pstSwtmrHandle);
                if (stSwtmrHandle.pfnHandler != NULL)
                {
                    stSwtmrHandle.pfnHandler(stSwtmrHandle.uwArg);
                }
            }
        }
    }//end of for
}

以上函數(shù)的運(yùn)行原理動(dòng)畫解析如下:

4.timer之間的對(duì)比
其實(shí)Tdengine的timer我之前已經(jīng)做過(guò)解讀了,200行代碼為大家解讀這個(gè)Github冠軍項(xiàng)目背后的定時(shí)器。就不加贅述了,這里把鴻蒙和Tdengine的timer做一下簡(jiǎn)單的對(duì)比:
節(jié)約關(guān)鍵資源:由于每個(gè)操作系統(tǒng)的timer都需要一個(gè)線程進(jìn)行回調(diào)處理,這對(duì)于Tdengine這種數(shù)據(jù)庫(kù)動(dòng)轍幾萬(wàn)個(gè)timer的應(yīng)用來(lái)說(shuō)是不可接受的,所以為了節(jié)省線程資源,Td要用自己實(shí)現(xiàn)的timer之所以要實(shí)現(xiàn)自己的定時(shí)器是為了節(jié)省線程資源。而鴻蒙實(shí)現(xiàn)timer則是為了節(jié)約硬件定時(shí)器資源。
最簡(jiǎn)化設(shè)計(jì):兩個(gè)timer都沒(méi)有優(yōu)先級(jí)的設(shè)定。其中鴻蒙OS做為移動(dòng)操作系統(tǒng)直接將timer的精度值也舍棄了。
使用雙鏈表提高效率:兩個(gè)timer都使用雙鏈表來(lái)存儲(chǔ)同一時(shí)刻到期的定時(shí)器,這樣能節(jié)省遍歷和移動(dòng)的時(shí)間,大大提高效率。

結(jié)語(yǔ)

從上面這兩個(gè)簡(jiǎn)單的模塊中我們也看到這些優(yōu)秀的項(xiàng)目都使用最精簡(jiǎn)的設(shè)計(jì),緊貼需求、甩掉包袱、輕裝上陣才能回歸本質(zhì)取得成功。
無(wú)論是TdEngine取消任務(wù)調(diào)度的優(yōu)先級(jí)排序,還是鴻蒙放棄對(duì)定時(shí)器精度的支持,都是看來(lái)出乎意料,實(shí)則頗具內(nèi)涵的減法操作。真正優(yōu)秀的項(xiàng)目都是敢于做減法的,只有減掉那些看似高大上的設(shè)計(jì),才能向著有取有舍,大道至簡(jiǎn)的境界邁進(jìn)。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
這位 GitHub 冠軍項(xiàng)目背后的“老男人”,堪稱 10 倍程序員本尊!
RTOS51
python線程定時(shí)器Timer(32)
如何在Linux下實(shí)現(xiàn)定時(shí)器
函數(shù)防抖
線程的使用 三種方式 Android中常用定時(shí)器
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服