小熊派IoT開發板華為物聯網操作系統LiteOS內核實戰教程05-互斥鎖

      網友投稿 688 2025-03-31

      1. LiteOS的互斥鎖


      1.1. 互斥鎖

      在多任務環境下,往往存在多個任務競爭同一共享資源的應用場景,互斥鎖可被用于對共享資源的保護從而實現獨占式訪問。互斥鎖(mutex)又稱互斥型信號量,是一種特殊的二值信號量,用于實現對共享資源的獨占式處理。另外,Huawei LiteOS提供的互斥鎖通過優先級繼承算法,解決了優先級翻轉問題。

      1.2. 互斥鎖的使用方式

      多任務環境下會存在多個任務訪問同一公共資源的場景,而有些公共資源是非共享的,需要任務進行獨占式處理。

      互斥鎖怎樣來避免這種沖突呢?

      在任意時刻,互斥鎖的狀態只有兩種:開鎖和閉鎖。

      當有任務持有時,互斥鎖處于閉鎖狀態,這個任務獲得該互斥鎖的所有權。當該任務釋放它時,該互斥鎖被開鎖,任務失去該互斥鎖的所有權。當一個任務持有互斥鎖時,其他任務將不能再對該互斥鎖進行開鎖或持有。

      那么,當一個互斥鎖為加鎖狀態時,此時其他任務如果想訪問這個公共資源則會被阻塞,直到互斥鎖被持有該鎖的任務釋放后,其他任務才能重新訪問該公共資源,此時互斥鎖再次上鎖,如此確保同一時刻只有一個任務正在訪問這個公共資源,保證了公共資源操作的完整性。

      1.3. 互斥鎖的使用場景

      互斥鎖可以提供任務之間的互斥機制,用來防止兩個任務在同一時刻訪問相同的共享資源。

      除此之外,互斥鎖還可以被用于防止多任務同步時造成優先級翻轉的問題。

      2. 互斥鎖API

      Huawei LiteOS 系統中的互斥鎖模塊為用戶提供創建/刪除互斥鎖、獲取/釋放互斥鎖的功能。

      Huawei LiteOS 系統中提供的互斥鎖 API 都是以 LOS 開頭,但是這些 API 使用起來比較復雜,所以本文中我們使用 Huawei IoT Link SDK 提供的統一API接口進行實驗,這些接口底層已經使用 LiteOS 提供的API實現,對用戶而言更為簡潔,API列表如下:

      osal的api接口聲明在中,使用相關的接口需要包含該頭文件,關于函數的詳細參數請參考該頭文件的聲明。

      相關的接口定義在osal.c中,基于LiteOS的接口實現在 liteos_imp.c文件中:

      2.1. osal_mutex_create

      osal_mutex_create接口用于創建一個互斥鎖,其接口原型如下:

      bool_t??osal_mutex_create(osal_mutex_t?*mutex){ ????bool_t?ret?=?false; ????if((NULL?!=?s_os_cb)?&&(NULL?!=?s_os_cb->ops)?&&(NULL?!=?s_os_cb->ops->mutex_create)) ????{ ????????ret?=?s_os_cb->ops->mutex_create(mutex); ????} ????return?ret;}

      小熊派IoT開發板華為物聯網操作系統LiteOS內核實戰教程05-互斥鎖

      該接口的參數說明如下表:

      2.2. osal_mutex_del

      osal_mutex_del接口用于刪除一個互斥鎖,其接口原型如下:

      bool_t??osal_mutex_del(osal_mutex_t?mutex){ ????bool_t?ret?=?false; ????if((NULL?!=?s_os_cb)?&&(NULL?!=?s_os_cb->ops)?&&(NULL?!=?s_os_cb->ops->mutex_del)) ????{ ????????ret?=?s_os_cb->ops->mutex_del(mutex); ????} ????return?ret;}

      該接口的參數說明如下表:

      2.3. osal_mutex_lock

      osal_mutex_lock接口用于獲取一個互斥鎖,其接口原型如下:

      bool_t??osal_mutex_lock(osal_mutex_t?mutex){ ????bool_t?ret?=?false; ????if((NULL?!=?s_os_cb)?&&(NULL?!=?s_os_cb->ops)?&&(NULL?!=?s_os_cb->ops->mutex_lock)) ????{ ????????ret?=?s_os_cb->ops->mutex_lock(mutex); ????} ????return?ret;}

      2.4. osal_mutex_unlock

      osal_mutex_unlock接口用于釋放一個互斥鎖,如果有任務阻塞等待該互斥鎖,則喚醒最早被阻塞的任務,該任務進入就緒態,并進行調度。

      其接口原型如下:

      bool_t??osal_mutex_unlock(osal_mutex_t?mutex){ ????bool_t?ret?=?false; ????if((NULL?!=?s_os_cb)?&&(NULL?!=?s_os_cb->ops)?&&(NULL?!=?s_os_cb->ops->mutex_unlock)) ????{ ????????ret?=?s_os_cb->ops->mutex_unlock(mutex); ????} ????return?ret;}

      該接口的參數說明如下表:

      3. 動手實驗 —— 使用互斥鎖進行資源保護

      實驗內容

      本實驗中將創建兩個任務,一個低優先級任務task1,一個高優先級任務task2,兩個任務之間依次對共享資源上鎖、操作、解鎖,在串口終端中觀察兩個任務的運行情況。

      實驗代碼

      首先打開上一篇使用的 HelloWorld 工程,基于此工程進行實驗。

      在Demo文件夾右擊,新建文件夾osal_kernel_demo用于存放內核的實驗文件(如果已有請忽略這一步)。

      接下來在此文件夾中新建一個實驗文件?osal_mutex_demo.c,開始編寫代碼:

      /*?使用osal接口需要包含該頭文件?*/#include?/*?任務優先級宏定義(shell任務的優先級為10)?*/#define?USER_TASK1_PRI??12??//低優先級#define?USER_TASK2_PRI??11??//高優先級/*?共享資源?*/uint32_t?public_value?=?0;/*?互斥鎖索引ID?*/osal_mutex_t?public_value_mutex;/*?任務task1入口函數?*/static?int?user_task1_entry(){ ????while(1) ????{ ????????/*?嘗試獲取互斥鎖?*/ ????????if(true?==?osal_mutex_lock(public_value_mutex)) ????????{ ????????????/*?獲取到互斥鎖,對共享資源進行操作?*/ ????????????printf("\r\ntask1:?lock?a?mutex.\r\n"); ????????????public_value?+=?10; ????????????printf("task1:?public_value?=?%ld.\r\n",?public_value); ????????????/*?對共享資源操作完畢,釋放互斥鎖?*/ ????????????printf("task1:?unlock?a?mutex.\r\n\r\n"); ????????????osal_mutex_unlock(public_value_mutex); ????????????/*?滿足條件則結束任務?*/ ????????????if(public_value?>?100) ????????????????break; ????????} ????} ????/*?while(1)會執行結束,所以需要返回值?*/ ????return?0;}/*?任務task2入口函數?*/static?int?user_task2_entry(){ ????while?(1) ????{ ????????/*?嘗試獲取互斥鎖?*/ ???????if(true?==?osal_mutex_lock(public_value_mutex)) ????????{ ????????????/*?獲取到互斥鎖,對共享資源進行操作?*/ ????????????printf("\r\ntask2:?lock?a?mutex.\r\n"); ????????????public_value?+=?5;? ????????????printf("task2:?public_value?=?%ld.\r\n",?public_value); ????????????/*?對共享資源操作完畢,釋放互斥鎖?*/ ????????????printf("task2:?unlock?a?mutex.\r\n\r\n"); ????????????osal_mutex_unlock(public_value_mutex); ????????????/*?滿足條件則結束任務?*/ ????????????if(public_value?>?90) ????????????????break; ????????????/*?優先級較高,需要掛起一下,讓task1獲取到互斥鎖,否則task2再次上鎖,形成死鎖?*/ ????????????osal_task_sleep(10); ????????} ????} ????/*?while(1)會執行結束,所以需要返回值?*/ ????return?0;}/*?標準demo啟動函數,函數名不要修改,否則會影響下一步實驗?*/int?standard_app_demo_main(){ ????/*?創建互斥鎖public_value_mutex?*/ ????osal_mutex_create(&public_value_mutex); ????/*?創建任務task1?*/ ????osal_task_create("user_task1",user_task1_entry,NULL,0x400,NULL,USER_TASK1_PRI); ????/*?創建任務task2?*/ ????osal_task_create("user_task2",user_task2_entry,NULL,0x400,NULL,USER_TASK2_PRI); ????return?0;}

      編寫完成之后,要將我們編寫的 osal_mutex_demo.c文件添加到makefile中,加入整個工程的編譯:

      這里有個較為簡單的方法,直接修改Demo文件夾下的user_demo.mk配置文件,添加如下代碼:

      #example?for?osal_mutex_demo ifeq?($(CONFIG_USER_DEMO),?"osal_mutex_demo")???? ????user_demo_src??=?${wildcard?$(TOP_DIR)/targets/STM32L431_BearPi/Demos/osal_kernel_demo/osal_mutex_demo.c} endif

      添加位置如圖:

      這段代碼的意思是:

      如果 CONFIG_USER_DEMO 宏定義的值是osal_mutex_demo,則將osal_mutex_demo.c文件加入到makefile中進行編譯。

      那么,如何配置 CONFIG_USER_DEMO 宏定義呢?在工程根目錄下的.sdkconfig文件中的末尾即可配置:

      因為我們修改了mk配置文件,所以點擊重新編譯按鈕進行編譯,編譯完成后點擊下載按鈕燒錄程序。

      實驗現象

      程序燒錄之后,即可看到程序已經開始運行,在串口終端中可看到實驗的輸出內容:

      **Link**main:V1.2.1?AT?11:30:59?ON?Nov?28?2019 WELCOME?TO?IOT_LINK?SHELL LiteOS:/> task2:?lock?a?mutex. task2:?public_value?=?5. task2:?unlock?a?mutex. task1:?lock?a?mutex. task1:?public_value?=?15. task1:?unlock?a?mutex. task1:?lock?a?mutex. task1:?public_value?=?25. task1:?unlock?a?mutex. task2:?lock?a?mutex. task2:?public_value?=?30. task2:?unlock?a?mutex. task1:?lock?a?mutex. task1:?public_value?=?40. task1:?unlock?a?mutex. task1:?lock?a?mutex. task1:?public_value?=?50. task1:?unlock?a?mutex. task2:?lock?a?mutex. task2:?public_value?=?55. task2:?unlock?a?mutex. task1:?lock?a?mutex. task1:?public_value?=?65. task1:?unlock?a?mutex. task1:?lock?a?mutex. task1:?public_value?=?75. task1:?unlock?a?mutex. task2:?lock?a?mutex. task2:?public_value?=?80. task2:?unlock?a?mutex. task1:?lock?a?mutex. task1:?public_value?=?90. task1:?unlock?a?mutex. task1:?lock?a?mutex. task1:?public_value?=?100. task1:?unlock?a?mutex. task2:?lock?a?mutex. task2:?public_value?=?105. task2:?unlock?a?mutex.

      可以看到,系統啟動后,首先打印版本號,串口shell的優先級為10,最先打印shell信息,接下來task1先創建,但是優先級較低,所以后創建的task2搶占執行,task2獲取到互斥鎖,對共享資源進行操作,操作完畢解鎖,然后主動掛起,task1獲取到互斥鎖,對共享資源進行另一個操作,操作完畢解鎖,在task1操作的時候,task2早已掛起完畢,但是獲取不到互斥鎖,所以掛起等待,在task1解鎖后,堵塞的task2被喚醒開始執行。

      關注“小熊派開源社區”微信公眾號,回復“LiteOS內核實戰”獲取實戰源代碼。

      小熊派開源社區,專注于IoT、AI、5G等前沿技術分享,關注“小熊派開源社區”微信公眾號,獲取更多資料教程。

      IoT 小熊派 LiteOS IoT 物聯網

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:excel2003拖動完成填充序號的方法
      下一篇:t檢驗在哪(t檢驗怎么看)
      相關文章
      亚洲欧洲∨国产一区二区三区| 亚洲精品国产高清在线观看| 亚洲变态另类一区二区三区 | 西西人体44rt高清亚洲| 亚洲综合色在线观看亚洲| 亚洲国产成人乱码精品女人久久久不卡 | 亚洲国产成人无码av在线播放| 亚洲狠狠综合久久| 老司机亚洲精品影院无码| 亚洲A∨无码一区二区三区 | 亚洲AV一宅男色影视| 亚洲天堂久久精品| 亚洲高清日韩精品第一区| 亚洲黄色高清视频| 亚洲人成毛片线播放| 亚洲人成人网毛片在线播放| 亚洲一区二区三区写真| 亚洲AV无码一区二区三区性色| 亚洲AV日韩综合一区| 无码专区一va亚洲v专区在线 | 亚洲同性男gay网站在线观看| 亚洲国产精品yw在线观看| 国产.亚洲.欧洲在线| 亚洲熟妇AV乱码在线观看| 日韩国产精品亚洲а∨天堂免| 亚洲av成人一区二区三区观看在线 | 亚洲精品偷拍视频免费观看| 久久精品国产精品亚洲人人| 亚洲日产无码中文字幕| 亚洲AV成人一区二区三区AV| 亚洲福利视频一区二区三区| 激情内射亚洲一区二区三区爱妻| 久久亚洲精品成人综合| 亚洲伊人久久大香线蕉综合图片| 亚洲AV午夜福利精品一区二区| 亚洲视频在线观看网址| 亚洲AV无码专区在线亚| 亚洲乱理伦片在线观看中字| 日本中文一区二区三区亚洲| 国产亚洲精品精品国产亚洲综合| 国产国拍亚洲精品mv在线观看|