chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

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

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

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

鴻蒙內(nèi)核源碼分析:進(jìn)程間異步解耦大數(shù)據(jù)傳遞

鴻蒙系統(tǒng)HarmonyOS ? 來(lái)源:my.oschina ? 作者:鴻蒙內(nèi)核源碼分析 ? 2021-04-24 11:32 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

基本概念

隊(duì)列又稱(chēng)消息隊(duì)列,是一種常用于任務(wù)間通信的數(shù)據(jù)結(jié)構(gòu)。隊(duì)列接收來(lái)自任務(wù)或中斷的不固定長(zhǎng)度消息,并根據(jù)不同的接口確定傳遞的消息是否存放在隊(duì)列空間中。

任務(wù)能夠從隊(duì)列里面讀取消息,當(dāng)隊(duì)列中的消息為空時(shí),掛起讀取任務(wù);當(dāng)隊(duì)列中有新消息時(shí),掛起的讀取任務(wù)被喚醒并處理新消息。任務(wù)也能夠往隊(duì)列里寫(xiě)入消息,當(dāng)隊(duì)列已經(jīng)寫(xiě)滿(mǎn)消息時(shí),掛起寫(xiě)入任務(wù);當(dāng)隊(duì)列中有空閑消息節(jié)點(diǎn)時(shí),掛起的寫(xiě)入任務(wù)被喚醒并寫(xiě)入消息。如果將讀隊(duì)列和寫(xiě)隊(duì)列的超時(shí)時(shí)間設(shè)置為0,則不會(huì)掛起任務(wù),接口會(huì)直接返回,這就是非阻塞模式。

消息隊(duì)列提供了異步處理機(jī)制,允許將一個(gè)消息放入隊(duì)列,但不立即處理。同時(shí)隊(duì)列還有緩沖消息的作用。

隊(duì)列用于任務(wù)間通信,可以實(shí)現(xiàn)消息的異步處理。同時(shí)消息的發(fā)送方和接收方不需要彼此聯(lián)系,兩者間是解耦的。

隊(duì)列特性

消息以先進(jìn)先出的方式排隊(duì),支持異步讀寫(xiě)。

讀隊(duì)列和寫(xiě)隊(duì)列都支持超時(shí)機(jī)制。

每讀取一條消息,就會(huì)將該消息節(jié)點(diǎn)設(shè)置為空閑。

發(fā)送消息類(lèi)型由通信雙方約定,可以允許不同長(zhǎng)度(不超過(guò)隊(duì)列的消息節(jié)點(diǎn)大?。┑南?。

一個(gè)任務(wù)能夠從任意一個(gè)消息隊(duì)列接收和發(fā)送消息。

多個(gè)任務(wù)能夠從同一個(gè)消息隊(duì)列接收和發(fā)送消息。

創(chuàng)建隊(duì)列時(shí)所需的隊(duì)列空間,默認(rèn)支持接口內(nèi)系統(tǒng)自行動(dòng)態(tài)申請(qǐng)內(nèi)存的方式,同時(shí)也支持將用戶(hù)分配的隊(duì)列空間作為接口入?yún)魅氲姆绞健?/p>

消息隊(duì)列長(zhǎng)什么樣?

#ifndef LOSCFG_BASE_IPC_QUEUE_LIMIT
#define LOSCFG_BASE_IPC_QUEUE_LIMIT 1024 //隊(duì)列個(gè)數(shù)
#endif
LITE_OS_SEC_BSS LosQueueCB *g_allQueue = NULL;//消息隊(duì)列池
LITE_OS_SEC_BSS STATIC LOS_DL_LIST g_freeQueueList;//空閑隊(duì)列鏈表,管分配的,需要隊(duì)列從這里申請(qǐng)

typedef struct {
    UINT8 *queueHandle; /**< Pointer to a queue handle */	//指向隊(duì)列句柄的指針
    UINT16 queueState; /**< Queue state */	//隊(duì)列狀態(tài)
    UINT16 queueLen; /**< Queue length */	//隊(duì)列中消息總數(shù)的上限值,由創(chuàng)建時(shí)確定,不再改變
    UINT16 queueSize; /**< Node size */		//消息節(jié)點(diǎn)大小,由創(chuàng)建時(shí)確定,不再改變,即定義了每個(gè)消息長(zhǎng)度的上限.
    UINT32 queueID; /**< queueID */			//隊(duì)列ID
    UINT16 queueHead; /**< Node head */		//消息頭節(jié)點(diǎn)位置(數(shù)組下標(biāo))
    UINT16 queueTail; /**< Node tail */		//消息尾節(jié)點(diǎn)位置(數(shù)組下標(biāo))
    UINT16 readWriteableCnt[OS_QUEUE_N_RW]; /**< Count of readable or writable resources, 0:readable, 1:writable */
											//隊(duì)列中可寫(xiě)或可讀消息數(shù),0表示可讀,1表示可寫(xiě)
    LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]; /**< the linked list to be read or written, 0:readlist, 1:writelist */
											//掛的都是等待讀/寫(xiě)消息的任務(wù)鏈表,0表示讀消息的鏈表,1表示寫(xiě)消息的任務(wù)鏈表
    LOS_DL_LIST memList; /**< Pointer to the memory linked list */	//@note_why 這里尚未搞明白是啥意思 ,是共享內(nèi)存嗎?
} LosQueueCB;//讀寫(xiě)隊(duì)列分離

解讀

和進(jìn)程,線程,定時(shí)器一樣,消息隊(duì)列也由全局統(tǒng)一的消息隊(duì)列池管理,池有多大?默認(rèn)是1024

鴻蒙內(nèi)核對(duì)消息的總個(gè)數(shù)有限制,queueLen消息總數(shù)的上限,在創(chuàng)建隊(duì)列的時(shí)候需指定,不能更改.

對(duì)每個(gè)消息的長(zhǎng)度也有限制,queueSize規(guī)定了消息的大小,也是在創(chuàng)建的時(shí)候指定.

為啥要指定總個(gè)數(shù)和每個(gè)的總大小,是因?yàn)閮?nèi)核一次性會(huì)把隊(duì)列的總內(nèi)存(queueLen*queueSize)申請(qǐng)下來(lái),確保不會(huì)出現(xiàn)后續(xù)使用過(guò)程中內(nèi)存不夠的問(wèn)題出現(xiàn),但同時(shí)也帶來(lái)了內(nèi)存的浪費(fèi),因?yàn)楹芸赡艽蟛糠謺r(shí)間隊(duì)列并沒(méi)有跑滿(mǎn).

隊(duì)列的讀取由queueHead,queueTail管理,Head表示隊(duì)列中被占用的消息節(jié)點(diǎn)的起始位置。Tail表示被占用的消息節(jié)點(diǎn)的結(jié)束位置,也是空閑消息節(jié)點(diǎn)的起始位置。隊(duì)列剛創(chuàng)建時(shí),Head和Tail均指向隊(duì)列起始位置

寫(xiě)隊(duì)列時(shí),根據(jù)readWriteableCnt[1]判斷隊(duì)列是否可以寫(xiě)入,不能對(duì)已滿(mǎn)(readWriteableCnt[1]為0)隊(duì)列進(jìn)行寫(xiě)操作。寫(xiě)隊(duì)列支持兩種寫(xiě)入方式:向隊(duì)列尾節(jié)點(diǎn)寫(xiě)入,也可以向隊(duì)列頭節(jié)點(diǎn)寫(xiě)入。尾節(jié)點(diǎn)寫(xiě)入時(shí),根據(jù)Tail找到起始空閑消息節(jié)點(diǎn)作為數(shù)據(jù)寫(xiě)入對(duì)象,如果Tail已經(jīng)指向隊(duì)列尾部則采用回卷方式。頭節(jié)點(diǎn)寫(xiě)入時(shí),將Head的前一個(gè)節(jié)點(diǎn)作為數(shù)據(jù)寫(xiě)入對(duì)象,如果Head指向隊(duì)列起始位置則采用回卷方式。

讀隊(duì)列時(shí),根據(jù)readWriteableCnt[0]判斷隊(duì)列是否有消息需要讀取,對(duì)全部空閑(readWriteableCnt[0]為0)隊(duì)列進(jìn)行讀操作會(huì)引起任務(wù)掛起。如果隊(duì)列可以讀取消息,則根據(jù)Head找到最先寫(xiě)入隊(duì)列的消息節(jié)點(diǎn)進(jìn)行讀取。如果Head已經(jīng)指向隊(duì)列尾部則采用回卷方式。

刪除隊(duì)列時(shí),根據(jù)隊(duì)列ID找到對(duì)應(yīng)隊(duì)列,把隊(duì)列狀態(tài)置為未使用,把隊(duì)列控制塊置為初始狀態(tài)。如果是通過(guò)系統(tǒng)動(dòng)態(tài)申請(qǐng)內(nèi)存方式創(chuàng)建的隊(duì)列,還會(huì)釋放隊(duì)列所占內(nèi)存。

留意readWriteList,這又是兩個(gè)雙向鏈表, 雙向鏈表是內(nèi)核最重要的結(jié)構(gòu)體,牢牢的寄生在宿主結(jié)構(gòu)體上.readWriteList上掛的是未來(lái)讀/寫(xiě)消息隊(duì)列的任務(wù)列表.

初始化隊(duì)列

LITE_OS_SEC_TEXT_INIT UINT32 OsQueueInit(VOID)//消息隊(duì)列模塊初始化
{
    LosQueueCB *queueNode = NULL;
    UINT32 index;
    UINT32 size;

    size = LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB);//支持1024個(gè)IPC隊(duì)列
    /* system resident memory, don't free */
    g_allQueue = (LosQueueCB *)LOS_MemAlloc(m_aucSysMem0, size);//常駐內(nèi)存
    if (g_allQueue == NULL) {
        return LOS_ERRNO_QUEUE_NO_MEMORY;
    }
    (VOID)memset_s(g_allQueue, size, 0, size);//清0
    LOS_ListInit(&g_freeQueueList);//初始化空閑鏈表
    for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {//循環(huán)初始化每個(gè)消息隊(duì)列
        queueNode = ((LosQueueCB *)g_allQueue) + index;//一個(gè)一個(gè)來(lái)
        queueNode->queueID = index;//這可是 隊(duì)列的身份證
        LOS_ListTailInsert(&g_freeQueueList, &queueNode->readWriteList[OS_QUEUE_WRITE]);//通過(guò)寫(xiě)節(jié)點(diǎn)掛到空閑隊(duì)列鏈表上
    }//這里要注意是用 readWriteList 掛到 g_freeQueueList鏈上的,所以要通過(guò) GET_QUEUE_LIST 來(lái)找到 LosQueueCB

    if (OsQueueDbgInitHook() != LOS_OK) {//調(diào)試隊(duì)列使用的.
        return LOS_ERRNO_QUEUE_NO_MEMORY;
    }
    return LOS_OK;
}

解讀

初始隊(duì)列模塊,對(duì)幾個(gè)全局變量賦值,創(chuàng)建消息隊(duì)列池,所有池都是常駐內(nèi)存,關(guān)于池后續(xù)有專(zhuān)門(mén)的文章整理,到目前為止已經(jīng)解除到了進(jìn)程池,任務(wù)池,定時(shí)器池,隊(duì)列池,==

將LOSCFG_BASE_IPC_QUEUE_LIMIT個(gè)隊(duì)列掛到空閑鏈表g_freeQueueList上,供后續(xù)分配和回收.熟悉內(nèi)核全局資源管理的對(duì)這種方式應(yīng)該不會(huì)再陌生.

創(chuàng)建隊(duì)列

//創(chuàng)建一個(gè)隊(duì)列,根據(jù)用戶(hù)傳入隊(duì)列長(zhǎng)度和消息節(jié)點(diǎn)大小來(lái)開(kāi)辟相應(yīng)的內(nèi)存空間以供該隊(duì)列使用,參數(shù)queueID帶走隊(duì)列ID
LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueCreate(CHAR *queueName, UINT16 len, UINT32 *queueID,
                                             UINT32 flags, UINT16 maxMsgSize)
{
    LosQueueCB *queueCB = NULL;
    UINT32 intSave;
    LOS_DL_LIST *unusedQueue = NULL;
    UINT8 *queue = NULL;
    UINT16 msgSize;

    (VOID)queueName;
    (VOID)flags;

    if (queueID == NULL) {
        return LOS_ERRNO_QUEUE_CREAT_PTR_NULL;
    }

    if (maxMsgSize > (OS_NULL_SHORT - sizeof(UINT32))) {// maxMsgSize上限 為啥要減去 sizeof(UINT32) ,因?yàn)榍懊娲娴氖顷?duì)列的大小
        return LOS_ERRNO_QUEUE_SIZE_TOO_BIG;
    }

    if ((len == 0) || (maxMsgSize == 0)) {
        return LOS_ERRNO_QUEUE_PARA_ISZERO;
    }

    msgSize = maxMsgSize + sizeof(UINT32);//總size = 消息體內(nèi)容長(zhǎng)度 + 消息大小(UINT32) 
    /*
     * Memory allocation is time-consuming, to shorten the time of disable interrupt,
     * move the memory allocation to here.
     *///內(nèi)存分配非常耗時(shí),為了縮短禁用中斷的時(shí)間,將內(nèi)存分配移到此處,用的時(shí)候分配隊(duì)列內(nèi)存
    queue = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, (UINT32)len * msgSize);//從系統(tǒng)內(nèi)存池中分配,由這里提供讀寫(xiě)隊(duì)列的內(nèi)存
    if (queue == NULL) {//這里是一次把隊(duì)列要用到的所有最大內(nèi)存都申請(qǐng)下來(lái)了,能保證不會(huì)出現(xiàn)后續(xù)使用過(guò)程中內(nèi)存不夠的問(wèn)題出現(xiàn)
        return LOS_ERRNO_QUEUE_CREATE_NO_MEMORY;//調(diào)用處有 OsSwtmrInit sys_mbox_new DoMqueueCreate ==
    }

    SCHEDULER_LOCK(intSave);
    if (LOS_ListEmpty(&g_freeQueueList)) {//沒(méi)有空余的隊(duì)列ID的處理,注意軟時(shí)鐘定時(shí)器是由 g_swtmrCBArray統(tǒng)一管理的,里面有正在使用和可分配空閑的隊(duì)列
        SCHEDULER_UNLOCK(intSave);//g_freeQueueList是管理可用于分配的隊(duì)列鏈表,申請(qǐng)消息隊(duì)列的ID需要向它要
        OsQueueCheckHook();
        (VOID)LOS_MemFree(m_aucSysMem1, queue);//沒(méi)有就要釋放 queue申請(qǐng)的內(nèi)存
        return LOS_ERRNO_QUEUE_CB_UNAVAILABLE;
    }

    unusedQueue = LOS_DL_LIST_FIRST(&g_freeQueueList);//找到一個(gè)沒(méi)有被使用的隊(duì)列
    LOS_ListDelete(unusedQueue);//將自己從g_freeQueueList中摘除, unusedQueue只是個(gè) LOS_DL_LIST 結(jié)點(diǎn).
    queueCB = GET_QUEUE_LIST(unusedQueue);//通過(guò)unusedQueue找到整個(gè)消息隊(duì)列(LosQueueCB)
    queueCB->queueLen = len;	//隊(duì)列中消息的總個(gè)數(shù),注意這個(gè)一旦創(chuàng)建是不能變的.
    queueCB->queueSize = msgSize;//消息節(jié)點(diǎn)的大小,注意這個(gè)一旦創(chuàng)建也是不能變的.
    queueCB->queueHandle = queue;	//隊(duì)列句柄,隊(duì)列內(nèi)容存儲(chǔ)區(qū). 
    queueCB->queueState = OS_QUEUE_INUSED;	//隊(duì)列狀態(tài)使用中
    queueCB->readWriteableCnt[OS_QUEUE_READ] = 0;//可讀資源計(jì)數(shù),OS_QUEUE_READ(0):可讀.
    queueCB->readWriteableCnt[OS_QUEUE_WRITE] = len;//可些資源計(jì)數(shù) OS_QUEUE_WRITE(1):可寫(xiě), 默認(rèn)len可寫(xiě).
    queueCB->queueHead = 0;//隊(duì)列頭節(jié)點(diǎn)
    queueCB->queueTail = 0;//隊(duì)列尾節(jié)點(diǎn)
    LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_READ]);//初始化可讀隊(duì)列鏈表
    LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_WRITE]);//初始化可寫(xiě)隊(duì)列鏈表
    LOS_ListInit(&queueCB->memList);//

    OsQueueDbgUpdateHook(queueCB->queueID, OsCurrTaskGet()->taskEntry);//在創(chuàng)建或刪除隊(duì)列調(diào)試信息時(shí)更新任務(wù)條目
    SCHEDULER_UNLOCK(intSave);

    *queueID = queueCB->queueID;//帶走隊(duì)列ID
    return LOS_OK;
}

解讀

創(chuàng)建和初始化一個(gè)LosQueueCB

動(dòng)態(tài)分配內(nèi)存來(lái)保存消息內(nèi)容,LOS_MemAlloc(m_aucSysMem1, (UINT32)len * msgSize);

msgSize = maxMsgSize + sizeof(UINT32);頭四個(gè)字節(jié)放消息的長(zhǎng)度,但消息最大長(zhǎng)度不能超過(guò)maxMsgSize

readWriteableCnt記錄讀/寫(xiě)隊(duì)列的數(shù)量,獨(dú)立計(jì)算

readWriteList掛的是等待讀取隊(duì)列的任務(wù)鏈表 將在OsTaskWait(&queueCB->readWriteList[readWrite], timeout, TRUE);中將任務(wù)掛到鏈表上.

關(guān)鍵函數(shù)OsQueueOperate

隊(duì)列的讀寫(xiě)都要經(jīng)過(guò)OsQueueOperate

o4YBAGCDkTmAUbFPAADjqnMUAgo404.png

/************************************************
隊(duì)列操作.是讀是寫(xiě)由operateType定
本函數(shù)是消息隊(duì)列最重要的一個(gè)函數(shù),可以分析出讀取消息過(guò)程中
發(fā)生的細(xì)節(jié),涉及任務(wù)的喚醒和阻塞,阻塞鏈表任務(wù)的相互提醒.
************************************************/
UINT32 OsQueueOperate(UINT32 queueID, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize, UINT32 timeout)
{
    LosQueueCB *queueCB = NULL;
    LosTaskCB *resumedTask = NULL;
    UINT32 ret;
    UINT32 readWrite = OS_QUEUE_READ_WRITE_GET(operateType);//獲取讀/寫(xiě)操作標(biāo)識(shí)
    UINT32 intSave;

    SCHEDULER_LOCK(intSave);
    queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);//獲取對(duì)應(yīng)的隊(duì)列控制塊
    ret = OsQueueOperateParamCheck(queueCB, queueID, operateType, bufferSize);//參數(shù)檢查
    if (ret != LOS_OK) {
        goto QUEUE_END;
    }

    if (queueCB->readWriteableCnt[readWrite] == 0) {//根據(jù)readWriteableCnt判斷隊(duì)列是否有消息讀/寫(xiě)
        if (timeout == LOS_NO_WAIT) {//不等待直接退出
            ret = OS_QUEUE_IS_READ(operateType) ? LOS_ERRNO_QUEUE_ISEMPTY : LOS_ERRNO_QUEUE_ISFULL;
            goto QUEUE_END;
        }

        if (!OsPreemptableInSched()) {//不支持搶占式調(diào)度
            ret = LOS_ERRNO_QUEUE_PEND_IN_LOCK;
            goto QUEUE_END;
        }
		//任務(wù)等待,這里很重要啊,將自己從就緒列表摘除,讓出了CPU并發(fā)起了調(diào)度,并掛在readWriteList[readWrite]上,掛的都等待讀/寫(xiě)消息的task
        ret = OsTaskWait(&queueCB->readWriteList[readWrite], timeout, TRUE);//任務(wù)被喚醒后會(huì)回到這里執(zhí)行,什么時(shí)候會(huì)被喚醒?當(dāng)然是有消息的時(shí)候!
        if (ret == LOS_ERRNO_TSK_TIMEOUT) {//喚醒后如果超時(shí)了,返回讀/寫(xiě)消息失敗
            ret = LOS_ERRNO_QUEUE_TIMEOUT;
            goto QUEUE_END;//
        }
    } else {
        queueCB->readWriteableCnt[readWrite]--;//對(duì)應(yīng)隊(duì)列中計(jì)數(shù)器--,說(shuō)明一條消息只能被讀/寫(xiě)一次
    }

    OsQueueBufferOperate(queueCB, operateType, bufferAddr, bufferSize);//發(fā)起讀或?qū)戧?duì)列操作

    if (!LOS_ListEmpty(&queueCB->readWriteList[!readWrite])) {//如果還有任務(wù)在排著隊(duì)等待讀/寫(xiě)入消息(當(dāng)時(shí)不能讀/寫(xiě)的原因有可能當(dāng)時(shí)隊(duì)列滿(mǎn)了==)
        resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&queueCB->readWriteList[!readWrite]));//取出要讀/寫(xiě)消息的任務(wù)
        OsTaskWake(resumedTask);//喚醒任務(wù)去讀/寫(xiě)消息啊
        SCHEDULER_UNLOCK(intSave);
        LOS_MpSchedule(OS_MP_CPU_ALL);//讓所有CPU發(fā)出調(diào)度申請(qǐng),因?yàn)楹芸赡苣莻€(gè)要讀/寫(xiě)消息的隊(duì)列是由其他CPU執(zhí)行
        LOS_Schedule();//申請(qǐng)調(diào)度
        return LOS_OK;
    } else {
        queueCB->readWriteableCnt[!readWrite]++;//對(duì)應(yīng)隊(duì)列讀/寫(xiě)中計(jì)數(shù)器++
    }

QUEUE_END:
    SCHEDULER_UNLOCK(intSave);
    return ret;
}

解讀

queueID指定操作消息隊(duì)列池中哪個(gè)消息隊(duì)列

operateType表示本次是是讀/寫(xiě)消息

bufferAddr,bufferSize表示如果讀操作,用buf接走數(shù)據(jù),如果寫(xiě)操作,將buf寫(xiě)入隊(duì)列.

timeout只用于當(dāng)隊(duì)列中沒(méi)有讀/寫(xiě)內(nèi)容時(shí)的等待.

當(dāng)讀消息時(shí)發(fā)現(xiàn)隊(duì)列中沒(méi)有可讀的消息,此時(shí)timeout決定是否將任務(wù)掛入等待讀隊(duì)列任務(wù)鏈表

當(dāng)寫(xiě)消息時(shí)發(fā)現(xiàn)隊(duì)列中沒(méi)有空間用于寫(xiě)的消息,此時(shí)timeout決定是否將任務(wù)掛入等待寫(xiě)隊(duì)列任務(wù)鏈表

if (!LOS_ListEmpty(&queueCB->readWriteList[!readWrite]))最有意思的是這行代碼.

在一次讀消息完成后會(huì)立即喚醒寫(xiě)隊(duì)列任務(wù)鏈表的任務(wù),因?yàn)樽x完了就有了剩余空間,等待寫(xiě)隊(duì)列的任務(wù)往往是因?yàn)闆](méi)有空間而進(jìn)入等待狀態(tài).

在一次寫(xiě)消息完成后會(huì)立即喚醒讀隊(duì)列任務(wù)鏈表的任務(wù),因?yàn)閷?xiě)完了隊(duì)列就有了新消息,等待讀隊(duì)列的任務(wù)往往是因?yàn)殛?duì)列中沒(méi)有消息而進(jìn)入等待狀態(tài).

編程實(shí)例

創(chuàng)建一個(gè)隊(duì)列,兩個(gè)任務(wù)。任務(wù)1調(diào)用寫(xiě)隊(duì)列接口發(fā)送消息,任務(wù)2通過(guò)讀隊(duì)列接口接收消息。

通過(guò)LOS_TaskCreate創(chuàng)建任務(wù)1和任務(wù)2。

通過(guò)LOS_QueueCreate創(chuàng)建一個(gè)消息隊(duì)列。

在任務(wù)1 send_Entry中發(fā)送消息。

在任務(wù)2 recv_Entry中接收消息。

通過(guò)LOS_QueueDelete刪除隊(duì)列。

#include "los_task.h"
#include "los_queue.h"

static UINT32 g_queue;
#define BUFFER_LEN 50

VOID send_Entry(VOID)
{
    UINT32 i = 0;
    UINT32 ret = 0;
    CHAR abuf[] = "test is message x";
    UINT32 len = sizeof(abuf);

    while (i < 5) {
        abuf[len -2] = '0' + i;
        i++;

        ret = LOS_QueueWriteCopy(g_queue, abuf, len, 0);
        if(ret != LOS_OK) {
            dprintf("send message failure, error: %x\n", ret);
        }

        LOS_TaskDelay(5);
    }
}

VOID recv_Entry(VOID)
{
    UINT32 ret = 0;
    CHAR readBuf[BUFFER_LEN] = {0};
    UINT32 readLen = BUFFER_LEN;

    while (1) {
        ret = LOS_QueueReadCopy(g_queue, readBuf, &readLen, 0);
        if(ret != LOS_OK) {
            dprintf("recv message failure, error: %x\n", ret);
            break;
        }

        dprintf("recv message: %s\n", readBuf);
        LOS_TaskDelay(5);
    }

    while (LOS_OK != LOS_QueueDelete(g_queue)) {
        LOS_TaskDelay(1);
    }

    dprintf("delete the queue success!\n");
}

UINT32 Example_CreateTask(VOID)
{
    UINT32 ret = 0; 
    UINT32 task1, task2;
    TSK_INIT_PARAM_S initParam;

    initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)send_Entry;
    initParam.usTaskPrio = 9;
    initParam.uwStackSize = LOS_TASK_MIN_STACK_SIZE;
    initParam.pcName = "sendQueue";
#ifdef LOSCFG_KERNEL_SMP
    initParam.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());
#endif
    initParam.uwResved = LOS_TASK_STATUS_DETACHED;

    LOS_TaskLock();
    ret = LOS_TaskCreate(&task1, &initParam);
    if(ret != LOS_OK) {
        dprintf("create task1 failed, error: %x\n", ret);
        return ret;
    }

    initParam.pcName = "recvQueue";
    initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)recv_Entry;
    ret = LOS_TaskCreate(&task2, &initParam);
    if(ret != LOS_OK) {
        dprintf("create task2 failed, error: %x\n", ret);
        return ret;
    }

    ret = LOS_QueueCreate("queue", 5, &g_queue, 0, BUFFER_LEN);
    if(ret != LOS_OK) {
        dprintf("create queue failure, error: %x\n", ret);
    }

    dprintf("create the queue success!\n");
    LOS_TaskUnlock();
    return ret;
}

結(jié)果驗(yàn)證

create the queue success!
recv message: test is message 0
recv message: test is message 1
recv message: test is message 2
recv message: test is message 3
recv message: test is message 4
recv message failure, error: 200061d
delete the queue success!

總結(jié)

消息隊(duì)列解決任務(wù)間大數(shù)據(jù)的傳遞

以一種異步,解耦的方式實(shí)現(xiàn)任務(wù)通訊

全局由消息隊(duì)列池統(tǒng)一管理

在創(chuàng)建消息隊(duì)列時(shí)申請(qǐng)內(nèi)存塊存儲(chǔ)消息內(nèi)存.

讀/寫(xiě)操作統(tǒng)一管理,分開(kāi)執(zhí)行,A任務(wù)讀/寫(xiě)完消息后會(huì)立即喚醒等待寫(xiě)/讀的B任務(wù).

編輯:hfy

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

    關(guān)注

    0

    文章

    7

    瀏覽量

    6629
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

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

    、使用內(nèi)存空間等系統(tǒng)資源,并獨(dú)立于其它線程運(yùn)行。 鴻蒙內(nèi)核每個(gè)進(jìn)程內(nèi)的線程獨(dú)立運(yùn)行、獨(dú)立調(diào)度,當(dāng)前進(jìn)程內(nèi)線程的調(diào)度不受其它進(jìn)程內(nèi)線程的影響。
    的頭像 發(fā)表于 10-18 10:42 ?2578次閱讀
    <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ī)制篇)

    意義上所理解的線程呢。狹義上的后續(xù)有 鴻蒙內(nèi)核源碼分析(啟動(dòng)過(guò)程篇) 來(lái)說(shuō)明。不知道大家有沒(méi)有這種體會(huì),學(xué)一個(gè)東西的過(guò)程中要接觸很多新概念,尤其像 Java/android 的生態(tài),概
    發(fā)表于 10-14 14:00

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

    內(nèi)核源碼分析(時(shí)鐘管理篇) | 觸發(fā)調(diào)度最大的源動(dòng)力|-鴻蒙內(nèi)核源碼
    發(fā)表于 11-20 11:24

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

    (); 就是設(shè)置啟動(dòng)任務(wù),但此時(shí)啥都還沒(méi)開(kāi)始呢,Kprocess 進(jìn)程都沒(méi)創(chuàng)建,怎么會(huì)有大家一般意義上所理解的線程呢。狹義上的后續(xù)有 鴻蒙內(nèi)核源碼
    發(fā)表于 11-23 10:53

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

    ;為什么會(huì)這樣?另外兩個(gè)爸爸對(duì)應(yīng)的PID是 1和2,那進(jìn)程池里的0號(hào)進(jìn)程又去哪里了呢?全部文章進(jìn)入 >> 鴻蒙系統(tǒng)源碼分析(總目錄) 查看
    發(fā)表于 11-24 11:23

    HarmonyOS 內(nèi)核源碼分析(下)—電子書(shū)上線啦!

    的第十六章 進(jìn)程如何異步傳遞大數(shù)據(jù)第十七章 是
    發(fā)表于 04-01 17:33

    HarmonyOS內(nèi)核源碼分析(下)

    章 任務(wù)一對(duì)多和多對(duì)多的同步方案第十四章 內(nèi)核最高優(yōu)先級(jí)任務(wù)是誰(shuí)第十五章 內(nèi)核是如何描述CPU的第十六章 進(jìn)程如何
    發(fā)表于 04-02 15:56

    鴻蒙分布式任務(wù)調(diào)度——數(shù)據(jù)傳遞

    鴻蒙分布式任務(wù)調(diào)度之數(shù)據(jù)傳遞
    發(fā)表于 06-12 17:29

    OpenHarmony進(jìn)程是如何傳遞大數(shù)據(jù)

    (OsQueueDbgInitHook() != LOS_OK) {//調(diào)試隊(duì)列使用的.return LOS_ERRNO_QUEUE_NO_MEMORY;}return LOS_OK;}總結(jié):消息隊(duì)列解決任務(wù)大數(shù)據(jù)傳遞,以
    發(fā)表于 05-23 17:13

    鴻蒙內(nèi)核進(jìn)程為何要通訊?

    鴻蒙內(nèi)核默認(rèn)支持 64個(gè)進(jìn)程和128個(gè)任務(wù),由進(jìn)程池和任務(wù)池統(tǒng)一管理.內(nèi)核設(shè)計(jì)盡量不去打擾它們,讓各自過(guò)好各自的日子, 但大家畢竟在一口鍋里
    的頭像 發(fā)表于 04-24 11:28 ?3025次閱讀
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>進(jìn)程</b><b class='flag-5'>間</b>為何要通訊?

    鴻蒙內(nèi)核源碼分析:task是內(nèi)核調(diào)度的單元

    從系統(tǒng)的角度看,線程是競(jìng)爭(zhēng)系統(tǒng)資源的最小運(yùn)行單元。線程可以使用或等待CPU、使用內(nèi)存空間等系統(tǒng)資源,并獨(dú)立于其它線程運(yùn)行。 鴻蒙內(nèi)核每個(gè)進(jìn)程內(nèi)的線程獨(dú)立運(yùn)行、獨(dú)立調(diào)度,當(dāng)前進(jìn)程內(nèi)線程
    發(fā)表于 11-23 15:51 ?22次下載
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b>:task是<b class='flag-5'>內(nèi)核</b>調(diào)度的單元

    鴻蒙內(nèi)核源碼分析進(jìn)程和Task的就緒隊(duì)列對(duì)調(diào)度的作用

    鴻蒙內(nèi)核代碼中有兩個(gè)源文件是關(guān)于隊(duì)列的,一個(gè)是用于調(diào)度的隊(duì)列,另一個(gè)是用于線程通訊的IPC隊(duì)列。 鴻蒙內(nèi)核
    發(fā)表于 11-23 15:48 ?31次下載
    <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'>進(jìn)程</b>和Task的就緒隊(duì)列對(duì)調(diào)度的作用

    鴻蒙內(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)程
    發(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>:<b class='flag-5'>進(jìn)程</b>是<b class='flag-5'>內(nèi)核</b>的資源管理單元

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

    為何鴻蒙內(nèi)核源碼分析系列開(kāi)篇就說(shuō) LOS_DL_LIST ? 因?yàn)樗?b class='flag-5'>鴻蒙 LOS 內(nèi)核中無(wú)處
    發(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倉(cāng)】給 Harmoηy○S源碼逐行加上中文注解,詳細(xì)闡述設(shè)計(jì)細(xì)節(jié),助你快速精讀 Harmonyos內(nèi)核源碼
    發(fā)表于 04-09 14:40 ?17次下載