日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

LiteOS 消息队列

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

參考:【野火】物聯網操作系統 LiteOS 開發實戰指南

3 LiteOS消息隊列

3.1 消息隊列簡介

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

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

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

    LiteOs消息隊列運作圖

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

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

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

  • 兩種傳遞方式比較

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

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

    3.5.1 出隊阻塞

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

    3.5.2 入隊阻塞

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

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

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

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

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

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

  • UINT32 LOS_QueueCreate(CHAR *pcQueueName,//消息隊列的名稱,暫時未使用UINT16 usLen,// 隊列長度UINT32 *puwQueueID,//成功創建的隊列控制結構ID,需要用戶在創建前定義UINT32 uwFlags,//隊列參數,保留參數,暫時不使用UINT16 usMaxMsgSize )//最大消息字節 {... }// 隊列控制塊 typedef struct tagQueueCB {UINT8 *pucQueue; /**< 隊列指針 */UINT16 usQueueState; /**< 隊列狀態 */UINT16 usQueueLen; /**< 隊列中消息個數 */UINT16 usQueueSize; /**< 消息節點大小 */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() 函數創建,才能成功創建消息隊列

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

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

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

  • 3.6.3 消息隊列寫數據函數

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

  • 當寫入消息時,

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

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

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

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

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

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

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

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

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

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