日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

LiteOS 消息队列

發(fā)布時間:2023/12/14 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LiteOS 消息队列 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

參考:【野火】物聯(lián)網操作系統(tǒng) LiteOS 開發(fā)實戰(zhàn)指南

3 LiteOS消息隊列

3.1 消息隊列簡介

  • 消息隊列是一種常用于任務間通信的數據結構
  • 可以在任務與任務間中斷和任務間傳遞消息,實現(xiàn)接收來自任務或者中斷的不固定長度的消息,并根據不同的接口選擇傳遞消息是否存放在自己的空間
  • 消息隊列是一種異步的通信方式,用戶在處理業(yè)務時,消息隊列提供異步處理機制,允許將一個消息放入隊列,但并不立即處理它
  • 消息隊列使用時需要包含頭文件los_queue.h
  • 3.2 LiteOS消息隊列的特點

  • 消息以先進先出方式排隊,支持異步讀寫工作方式
  • 讀隊列和寫隊列都支持超時機制
  • 發(fā)送消息類型由通信雙方約定,可以允許不同長度(不超過隊列節(jié)點最大值)的任意類型消息
  • 消息支持先進后出的方式排隊,往隊首發(fā)送消息(LIFO)
  • 一個任務能夠從任意一個消息隊列接收和發(fā)送消息
  • 多個任務能夠從同一個消息隊列接收和發(fā)送消息
  • 當隊列使用結束后,如果是動態(tài)申請的內存,需要通過釋放內存函數回收
  • 3.3 LiteOs消息隊列的運作機制

  • 創(chuàng)建隊列時,用戶根據傳入的隊列長度消息節(jié)點來開辟相應的內存空間
  • 隊列控制塊中維護消息頭結點位置usQueueHead和一個消息尾節(jié)點位置usQueueTail來表示消息隊列的消息存儲情況
  • 可以將LiteOs消息隊列看成一個_環(huán)形隊列_
  • 寫隊列是從usQueueTail所指的尾部的空閑節(jié)點寫入區(qū)域,利用usReadWriteableCnt[OS_QUEUE_WRITE]來判斷是否可以寫入
  • 讀隊列是從usQueueHead找到最先入隊列的消息節(jié)點進行讀取,利用usReadWriteableCnt[OS_QUEUE_READ]判斷隊列是否有消息可讀取,若沒有消息的隊列進行讀隊列操作會引起任務掛起
  • 刪除隊列根據傳入的隊列ID尋找到對應的隊列,把隊列狀態(tài)設置為未使用,釋放原隊列所占空間
  • LiteOs的消息隊列采用兩個雙向鏈表來維護一個鏈表指向消息隊列的頭部,一個鏈表指向消息隊列的尾尾(stReadWriteList[QUEUE_HEAD_TAIL]),通過訪問這兩個鏈表就能直接訪問對應的消息空間,并且通過消息隊列控制塊 中的讀寫類型(usReadWriteableCnt[QUEUE_READ_WRITE])來操作消息隊列
  • 消息隊列的運作過程如下圖所示

    LiteOs消息隊列運作圖

    消息隊列讀寫消息圖
  • 3.4 LiteOs消息隊列的傳輸機制

  • 消息隊列是一種FIFO線性表,也支持LIFO

  • 消息數據傳輸支持值傳遞(拷貝)和引用傳遞

  • 兩種傳遞方式比較

    消息傳遞方式大小重要性
    拷貝數據量小的場合數據重要性高
    引用方式數據量大的場合重要性一般場合
  • 3.5 消息隊列的阻塞機制

    • 顧名思義,就是指讀/寫消息隊列時,能夠完整的不受其他任務干擾的完成讀/寫,即阻塞機制

    3.5.1 出隊阻塞

    • 讀操作,若消息隊列中沒有消息,會有三種選擇
      • 該任務繼續(xù)干別的事情,不會進入阻塞狀態(tài)
      • 該任務等待消息隊列的消息,等待時間由用戶定制,等待過程即為阻塞狀態(tài),消息隊列有了對應的消息后,該任務轉為就緒狀態(tài),然后根據該任務的優(yōu)先級讀取隊列消息,若超時,則該任務放棄等待,去干別的事情
      • 該任務死等,等不到消息就不干別的事情,該任務一直進入阻塞狀態(tài),直到完成讀取隊列的消息

    3.5.2 入隊阻塞

    • 寫操作,若消息隊列已經滿了,會進行如下處理
      • 發(fā)送消息操作的時候,當且僅當隊列被允許入隊時,發(fā)送者才能成功發(fā)送消息
      • 隊列中無可用消息空間時,系統(tǒng)會根據用戶指定的阻塞超時時間將任務阻塞,在指定的超時時間內如果還不能完成入隊操作,發(fā)送消息的任務或者中斷服務程序會收到一個錯誤代碼LOS_ERRNO_QUEUE_ISFULL ,然后解除阻塞狀態(tài)
      • 只有在任務中發(fā)送消息才允許進行阻塞狀態(tài),在中斷中發(fā)送消息不允許帶有阻塞機制的,否則返回錯誤代碼LOS_ERRNO_QUEUE_READ_IN_INTERRUPT
      • 如果有多個任務阻塞在一個消息隊列中,那么這些阻塞的任務將按照任務優(yōu)先級進行排序,優(yōu)先級高的任務將優(yōu)先獲得隊列的訪問權

    3.6 常用消息隊列的函數介紹

    3.6.1 使用隊列模塊的典型流程

  • 創(chuàng)建消息隊列LOS_QueueCreate,在創(chuàng)建任務之前
  • 創(chuàng)建成功后,可以得到消息隊列的ID值
  • 寫隊列操作函數LOS_QueueWrite ,在對應需要傳遞消息的任務中使用
  • 讀隊列操作函數LOS_QueueRead ,在對應需要讀取消息的任務中使用
  • 刪除隊列LOS_QueueDelete
  • 3.6.2 創(chuàng)建消息隊列LOS_QueueCreate()

  • 創(chuàng)建消息隊列的內存空間:
    內存空間=消息隊列控制塊大小+(單個消息空間大小+4字節(jié))?消息隊列長度內存空間=消息隊列控制塊大小+(單個消息空間大小+4字節(jié))*消息隊列長度 =++4節(jié)?

  • 當消息隊列被創(chuàng)建時,系統(tǒng)會為控制塊分配對應的內存空間,用于保存消息隊列的(消息存儲位置,頭指針,尾指針,消息大小,以及隊列長度等)

  • UINT32 LOS_QueueCreate(CHAR *pcQueueName,//消息隊列的名稱,暫時未使用UINT16 usLen,// 隊列長度UINT32 *puwQueueID,//成功創(chuàng)建的隊列控制結構ID,需要用戶在創(chuàng)建前定義UINT32 uwFlags,//隊列參數,保留參數,暫時不使用UINT16 usMaxMsgSize )//最大消息字節(jié) {... }// 隊列控制塊 typedef struct tagQueueCB {UINT8 *pucQueue; /**< 隊列指針 */UINT16 usQueueState; /**< 隊列狀態(tài) */UINT16 usQueueLen; /**< 隊列中消息個數 */UINT16 usQueueSize; /**< 消息節(jié)點大小 */UINT16 usQueueID; /**< 隊列ID */UINT16 usQueueHead; /**< 消息頭結點位置 */UINT16 usQueueTail; /**< 消息尾結點位置 */UINT16 usReadWriteableCnt[2]; /**< 可讀或者可寫資源的計數0:可讀,1:可寫 */LOS_DL_LIST stReadWriteList[2]; /**< 指向要讀取或寫入的鏈表的指針0: 讀列表 */LOS_DL_LIST stMemList; /** 指向內存鏈表的指針 */ } QUEUE_CB_S;
  • 先定義隊列ID,再調用LOS_QueueCreate() 函數創(chuàng)建,才能成功創(chuàng)建消息隊列

  • 3.6.2 消息隊列刪除函數LOS_QueueDelete()

  • 隊列刪除函數是直接根據隊列ID直接刪除的

    UINT32 LOS_QueueDelete(UINT32 uwQueueID)
  • 隊列在使用或者阻塞中是不能被刪除的

  • 3.6.3 消息隊列寫數據函數

  • 任務或者中斷程序都可以給消息隊列寫入消息

  • 當寫入消息時,

    • 如果隊列未滿,LiteOS會將消息拷貝到消息隊列的尾部,
    • 若滿,會根據用戶指定的阻塞超時時間進行阻塞,在這段時間中,如果隊列還是滿的,該任務將保持阻塞狀態(tài)以等待有空閑的消息空間,如果其他任務從其等待的隊列中讀取了數據,則消息隊列空出空間,該等待的任務自動由阻塞狀態(tài)轉為就緒態(tài),并寫入消息
    • 當任務等待的時間超過指定的阻塞時間,即使隊列中還是滿的,任務也會自動從阻塞狀態(tài)變?yōu)榫途w態(tài),此時發(fā)送消息的任務/中斷程序會收到一個錯誤碼:LOS_ERRNO_QUEUE_ISFULL
  • 不帶拷貝寫入函數LOS_QueueWrite():

    UINT32 LOS_QueueWrite(UINT32 uwQueueID, // 隊列IDVOID *pBufferAddr, // 存儲寫入的數據的起始地址UINT32 uwBufferSize, // 存入緩存區(qū)的大小UINT32 uwTimeOut); // 等待時間(0~LOS_WAIT_FOREVER)
  • 寫入隊列需要注意幾點:

    • 在使用寫入隊列的操作前應先創(chuàng)建要寫入的隊列
    • 在中斷上下文環(huán)境中, 必須使用非阻塞模式寫入,也就是等待時間為 0 個 tick
    • 在初始化 LiteOS 之前無法調用此 API
    • 將寫入由 uwBufferSize 指定大小的數據,其數據存儲在 BufferAddr 指定的地址 ,那么該數據地址必須有效,否則會發(fā)生錯誤
    • 寫入隊列節(jié)點中的是數據的地址
  • 帶拷貝寫入LOS_ QueueWriteCopy()

    UINT32 LOS_QueueWriteCopy(UINT32 uwQueueID, // 隊列IDVOID *pBufferAddr, // 存儲寫入的數據的起始地址UINT32 uwBufferSize, // 存入緩存區(qū)的大小UINT32 uwTimeOut); // 等待時間(0~LOS_WAIT_FOREVER)
  • 注意點同不帶拷貝寫入,區(qū)別是寫入隊列中的是存儲在pBufferAddr中的數據
  • 3.6.4 消息隊列讀數據函數

  • LOS_ QueueRead()(不帶拷貝方式讀出)

    UINT32 LOS_QueueRead(UINT32 uwQueueID, // 隊列IDVOID *pBufferAddr, // 存儲寫入的數據的起始地址UINT32 uwBufferSize, // 存入緩存區(qū)的大小UINT32 uwTimeOut); // 等待時間(0~LOS_WAIT_FOREVER)
  • 注意點:

    • 在使用讀取隊列的操作前應先創(chuàng)建要寫入的隊列
    • 隊列讀取采用的是先進先出(FIFO)模式, 首先讀取首先存儲在隊列中的數據
    • 必須要我們自己定義一個存儲讀取出來的數據的地方,并且把存儲數據的起始地址傳遞給 LOS_ QueueRead()函數,否則,將發(fā)生地址非法的錯誤。
    • 在中斷上下文環(huán)境中, 必須使用非阻塞模式寫入,也就是等待時間為 0 個 tick
    • 在初始化 LiteOS 之前無法調用此 API
    • pBufferAddr里存放的是隊列節(jié)點的地址
    • LOS_QueueReadCopy()和 LOS_QueueWriteCopy()是一組接口,LOS_QueueRead()和 LOS_QueueWrite()是一組接口,兩組接口需要配套使用
  • LOS_ QueueReadCopy()(帶拷貝讀出)

    UINT32 LOS_QueueReadCopy(UINT32 uwQueueID, // 隊列 IDVOID * pBufferAddr, // 存儲獲取數據的起始地址UINT32 * puwBufferSize,// 保存讀取之后數據大小的值UINT32 uwTimeOut) // 等待時間
  • 注意點同上,不同的是
    • pBufferAddr存放的是消息隊列中的數據
    • 需要定義一個空間保存讀取數據的大小
  • 總結

    以上是生活随笔為你收集整理的LiteOS 消息队列的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。