您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“LiteOS互斥鎖怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“LiteOS互斥鎖怎么使用”吧!
在多任務(wù)環(huán)境下,往往存在多個(gè)任務(wù)競爭同一共享資源的應(yīng)用場景,互斥鎖可被用于對共享資源的保護(hù)從而實(shí)現(xiàn)獨(dú)占式訪問?;コ怄i(mutex)又稱互斥型信號量,是一種特殊的二值信號量,用于實(shí)現(xiàn)對共享資源的獨(dú)占式處理。另外,Huawei LiteOS提供的互斥鎖通過優(yōu)先級繼承算法,解決了優(yōu)先級翻轉(zhuǎn)問題。
多任務(wù)環(huán)境下會存在多個(gè)任務(wù)訪問同一公共資源的場景,而有些公共資源是非共享的,需要任務(wù)進(jìn)行獨(dú)占式處理。
互斥鎖怎樣來避免這種沖突呢?
在任意時(shí)刻,互斥鎖的狀態(tài)只有兩種:開鎖和閉鎖。
當(dāng)有任務(wù)持有時(shí),互斥鎖處于閉鎖狀態(tài),這個(gè)任務(wù)獲得該互斥鎖的所有權(quán)。當(dāng)該任務(wù)釋放它時(shí),該互斥鎖被開鎖,任務(wù)失去該互斥鎖的所有權(quán)。當(dāng)一個(gè)任務(wù)持有互斥鎖時(shí),其他任務(wù)將不能再對該互斥鎖進(jìn)行開鎖或持有。
那么,當(dāng)一個(gè)互斥鎖為加鎖狀態(tài)時(shí),此時(shí)其他任務(wù)如果想訪問這個(gè)公共資源則會被阻塞,直到互斥鎖被持有該鎖的任務(wù)釋放后,其他任務(wù)才能重新訪問該公共資源,此時(shí)互斥鎖再次上鎖,如此確保同一時(shí)刻只有一個(gè)任務(wù)正在訪問這個(gè)公共資源,保證了公共資源操作的完整性。
互斥鎖可以提供任務(wù)之間的互斥機(jī)制,用來防止兩個(gè)任務(wù)在同一時(shí)刻訪問相同的共享資源。
除此之外,互斥鎖還可以被用于防止多任務(wù)同步時(shí)造成優(yōu)先級翻轉(zhuǎn)的問題。
Huawei LiteOS 系統(tǒng)中的互斥鎖模塊為用戶提供創(chuàng)建/刪除互斥鎖、獲取/釋放互斥鎖的功能。
Huawei LiteOS 系統(tǒng)中提供的互斥鎖 API 都是以 LOS 開頭,但是這些 API 使用起來比較復(fù)雜,所以本文中我們使用 Huawei IoT Link SDK 提供的統(tǒng)一API接口進(jìn)行實(shí)驗(yàn),這些接口底層已經(jīng)使用 LiteOS 提供的API實(shí)現(xiàn),對用戶而言更為簡潔,API列表如下:
osal的api接口聲明在<osal.h>中,使用相關(guān)的接口需要包含該頭文件,關(guān)于函數(shù)的詳細(xì)參數(shù)請參考該頭文件的聲明。
相關(guān)的接口定義在osal.c中,基于LiteOS的接口實(shí)現(xiàn)在 liteos_imp.c文件中:
接口名 | 功能描述 |
---|---|
osal_mutex_create | 創(chuàng)建互斥鎖 |
osal_mutex_del | 刪除互斥鎖 |
osal_mutex_lock | 獲取互斥鎖(上鎖) |
osal_mutex_unlock | 釋放互斥鎖(解鎖) |
osal_mutex_create
接口用于創(chuàng)建一個(gè)互斥鎖,其接口原型如下:
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; }
該接口的參數(shù)說明如下表:
參數(shù) | 描述 |
---|---|
mutex | 互斥鎖索引ID的地址 |
返回值 | false - 創(chuàng)建失敗 |
返回值 | true - 創(chuàng)建成功 |
osal_mutex_del
接口用于刪除一個(gè)互斥鎖,其接口原型如下:
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; }
該接口的參數(shù)說明如下表:
參數(shù) | 描述 |
---|---|
mutex | 互斥鎖索引ID |
返回值 | false - 刪除失敗 |
返回值 | true - 刪除成功 |
osal_mutex_lock
接口用于獲取一個(gè)互斥鎖,其接口原型如下:
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; }
參數(shù) | 描述 |
---|---|
mutex | 互斥鎖索引ID |
返回值 | false - 申請失敗 |
返回值 | true - 申請成功 |
osal_mutex_unlock
接口用于釋放一個(gè)互斥鎖,如果有任務(wù)阻塞等待該互斥鎖,則喚醒最早被阻塞的任務(wù),該任務(wù)進(jìn)入就緒態(tài),并進(jìn)行調(diào)度。
其接口原型如下:
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; }
該接口的參數(shù)說明如下表:
參數(shù) | 描述 |
---|---|
mutex | 互斥鎖索引ID |
返回值 | false - 釋放失敗 |
返回值 | true - 釋放成功 |
本實(shí)驗(yàn)中將創(chuàng)建兩個(gè)任務(wù),一個(gè)低優(yōu)先級任務(wù)task1,一個(gè)高優(yōu)先級任務(wù)task2,兩個(gè)任務(wù)之間依次對共享資源上鎖、操作、解鎖,在串口終端中觀察兩個(gè)任務(wù)的運(yùn)行情況。
首先打開上一篇使用的 HelloWorld 工程,基于此工程進(jìn)行實(shí)驗(yàn)。
在Demo文件夾右擊,新建文件夾osal_kernel_demo
用于存放內(nèi)核的實(shí)驗(yàn)文件(如果已有請忽略這一步)。
接下來在此文件夾中新建一個(gè)實(shí)驗(yàn)文件 osal_mutex_demo.c
,開始編寫代碼:
/* 使用osal接口需要包含該頭文件 */ #include <osal.h> /* 任務(wù)優(yōu)先級宏定義(shell任務(wù)的優(yōu)先級為10) */ #define USER_TASK1_PRI 12 //低優(yōu)先級 #define USER_TASK2_PRI 11 //高優(yōu)先級 /* 共享資源 */ uint32_t public_value = 0; /* 互斥鎖索引ID */ osal_mutex_t public_value_mutex; /* 任務(wù)task1入口函數(shù) */ static int user_task1_entry() { while(1) { /* 嘗試獲取互斥鎖 */ if(true == osal_mutex_lock(public_value_mutex)) { /* 獲取到互斥鎖,對共享資源進(jìn)行操作 */ 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); /* 滿足條件則結(jié)束任務(wù) */ if(public_value > 100) break; } } /* while(1)會執(zhí)行結(jié)束,所以需要返回值 */ return 0; } /* 任務(wù)task2入口函數(shù) */ static int user_task2_entry() { while (1) { /* 嘗試獲取互斥鎖 */ if(true == osal_mutex_lock(public_value_mutex)) { /* 獲取到互斥鎖,對共享資源進(jìn)行操作 */ 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); /* 滿足條件則結(jié)束任務(wù) */ if(public_value > 90) break; /* 優(yōu)先級較高,需要掛起一下,讓task1獲取到互斥鎖,否則task2再次上鎖,形成死鎖 */ osal_task_sleep(10); } } /* while(1)會執(zhí)行結(jié)束,所以需要返回值 */ return 0; } /* 標(biāo)準(zhǔn)demo啟動函數(shù),函數(shù)名不要修改,否則會影響下一步實(shí)驗(yàn) */ int standard_app_demo_main() { /* 創(chuàng)建互斥鎖public_value_mutex */ osal_mutex_create(&public_value_mutex); /* 創(chuàng)建任務(wù)task1 */ osal_task_create("user_task1",user_task1_entry,NULL,0x400,NULL,USER_TASK1_PRI); /* 創(chuàng)建任務(wù)task2 */ osal_task_create("user_task2",user_task2_entry,NULL,0x400,NULL,USER_TASK2_PRI); return 0; }
編寫完成之后,要將我們編寫的 osal_mutex_demo.c文件添加到makefile中,加入整個(gè)工程的編譯:
這里有個(gè)較為簡單的方法,直接修改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中進(jìn)行編譯。
那么,如何配置 CONFIG_USER_DEMO 宏定義呢?在工程根目錄下的.sdkconfig
文件中的末尾即可配置:
因?yàn)槲覀冃薷牧薽k配置文件,所以點(diǎn)擊重新編譯按鈕進(jìn)行編譯,編譯完成后點(diǎn)擊下載按鈕燒錄程序。
程序燒錄之后,即可看到程序已經(jīng)開始運(yùn)行,在串口終端中可看到實(shí)驗(yàn)的輸出內(nèi)容:
linkmain: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.
可以看到,系統(tǒng)啟動后,首先打印版本號,串口shell的優(yōu)先級為10,最先打印shell信息,接下來task1先創(chuàng)建,但是優(yōu)先級較低,所以后創(chuàng)建的task2搶占執(zhí)行,task2獲取到互斥鎖,對共享資源進(jìn)行操作,操作完畢解鎖,然后主動掛起,task1獲取到互斥鎖,對共享資源進(jìn)行另一個(gè)操作,操作完畢解鎖,在task1操作的時(shí)候,task2早已掛起完畢,但是獲取不到互斥鎖,所以掛起等待,在task1解鎖后,堵塞的task2被喚醒開始執(zhí)行。
到此,相信大家對“LiteOS互斥鎖怎么使用”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。