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

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

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

OpenHarmony內(nèi)核編程實(shí)戰(zhàn)

觸覺(jué)智能 ? 2024-03-27 08:31 ? 次閱讀

在正式開(kāi)始之前,對(duì)于剛接觸OpenHarmony的伙伴們,面對(duì)大篇幅的源碼可能無(wú)從下手,不知道怎么去編碼寫(xiě)程序,下面用一個(gè)簡(jiǎn)單的例子帶伙伴們?nèi)腴T(mén)。

▍任務(wù)編寫(xiě)程序,讓開(kāi)發(fā)板在串口調(diào)試工具中輸出”Hello,OpenHarmony“。

▍操作

在源碼的根目錄中有名為”applications“的文件,他存放著應(yīng)用程序樣例,下面是他的目錄結(jié)構(gòu):

5f464dbe-ebd1-11ee-9118-92fbcf53809c.png

我們要編寫(xiě)的程序樣例就在源碼根目錄下的:applications/sample/wifi-iot/app/下面將具體演示如何編寫(xiě)程序樣例。

1.新建樣例目錄applications/sample/wifi-iot/app/hello_demo

2.新建源文件和gn文件applications/sample/wifi-iot/app/hello_demo/hello.capplications/sample/wifi-iot/app/hello_demo/BUILD.gn

5f5cb612-ebd1-11ee-9118-92fbcf53809c.png

3.編寫(xiě)源文件hello.c

#include
#include"ohos_init.h"

voidhello(void){
printf("Hello,OpenHarmony!");
}

SYS_RUN(hello);

第一次操作的伙伴們可能會(huì)在引入”ohos_init.h“庫(kù)時(shí)報(bào)錯(cuò),面對(duì)這個(gè)問(wèn)題我們只需要修改我們的include path即可,一般我們直接在目錄下的 .vscode/c_cpp_properties.json文件中直接修改includePath

5f643acc-ebd1-11ee-9118-92fbcf53809c.png筆者的代碼版本是OpenHarmony3.2Release版,不同版本的源碼可能庫(kù)所存放的路徑不同,那么怎么去找到對(duì)應(yīng)的庫(kù)呢,對(duì)于不熟悉源碼結(jié)構(gòu)的伙伴們學(xué)習(xí)起來(lái)很不友好。對(duì)于在純Windows環(huán)境開(kāi)發(fā)的伙伴們,筆者推薦使用everything這款工具,它可以快速查找主機(jī)中的文件,比在資源管理器的搜索快上不少。5f7148ca-ebd1-11ee-9118-92fbcf53809c.pngeverything似乎不能找到我WSL中的Ubuntu中的文件,因此對(duì)于Windows + Linux環(huán)境下的伙伴們,這款工具又不那么適用。那就可以根據(jù)Linux的查詢(xún)指令來(lái)定位文件所在目錄,下面提供查詢(xún)案例防止有不熟悉Linux的伙伴們。我們使用locate指令來(lái)查找文件。首先安裝locate

sudoaptinstallmlocate

更新mlocate.db

sudoupdatedb

查詢(xún)文件目錄

locateohos_init.h

找到我們?cè)创a根目錄下 include路徑下的ohos_init.h文件

5f86a120-ebd1-11ee-9118-92fbcf53809c.png4.編寫(xiě)gn文件

static_library("sayHello"){
sources = [
"hello.c"
]
include_dirs = [
"http://commonlibrary/utils_lite/include"
]
}

static_library表示我們編寫(xiě)的靜態(tài)模塊,名為"sayHello", sources表示我們要編譯的源碼,include_dirs表示我們引入的庫(kù),這里的雙斜杠就代表我們的源碼根目錄,”/commonlibrary/utils_lite/include“就是我們ohos_init.h的所在目錄

5.編寫(xiě)app下的gn文件在app的目錄下也有一個(gè)gn文件,我們只需要去修改他即可5f94997e-ebd1-11ee-9118-92fbcf53809c.png

這表示我們的程序?qū)?huì)執(zhí)行hello_demo樣例中的sayHello模塊

6.編譯,燒錄,串口調(diào)試這一步就屬于基礎(chǔ)操作了,不做過(guò)多贅述,7.觀察控制臺(tái)的輸出5fa4e31a-ebd1-11ee-9118-92fbcf53809c.png

至此編碼完成了編碼入門(mén),下面就具體介紹OpenHarmony的內(nèi)核編程。

內(nèi)核

▍內(nèi)核介紹

什么是內(nèi)核?或者說(shuō)內(nèi)核在一個(gè)操作系統(tǒng)中起到一個(gè)什么樣的作用?相信初次接觸這個(gè)詞的伙伴們也會(huì)有同樣的疑問(wèn)。不過(guò)不用擔(dān)心,筆者會(huì)盡可能地通俗地介紹內(nèi)核的相關(guān)知識(shí),以便大家能夠更好地去體會(huì)內(nèi)核編程。

我們先來(lái)看一張圖,這是OpenHarmony官網(wǎng)發(fā)布的技術(shù)架構(gòu)圖5fb00a6a-ebd1-11ee-9118-92fbcf53809c.png

我們可以看到最底層叫做內(nèi)核層,有Linux,LiteOS等。內(nèi)核在整個(gè)架構(gòu),或者操作系統(tǒng)中起到一個(gè)核心作用,他負(fù)責(zé)管理計(jì)算機(jī)系統(tǒng)內(nèi)的資源和硬件設(shè)備,提供給頂層的應(yīng)用層一個(gè)統(tǒng)一規(guī)范的接口,從而使得整個(gè)系統(tǒng)能夠完成應(yīng)用與硬件的交互。

具體點(diǎn)來(lái)說(shuō),內(nèi)核可以做以下相關(guān)的工作:1.進(jìn)程管理2.內(nèi)存管理3.文件資源管理4.網(wǎng)絡(luò)通信管理5.設(shè)備驅(qū)動(dòng)管理當(dāng)然不局限于這些,這里只是給出具體的例子供伙伴們理解,如果實(shí)在難以理解,那么筆者再舉一個(gè)例子,進(jìn)程??赡苣銢](méi)聽(tīng)過(guò)進(jìn)程,但你一定打開(kāi)過(guò)任務(wù)管理器。5fc04650-ebd1-11ee-9118-92fbcf53809c.png

這些都是進(jìn)程,一個(gè)進(jìn)程又由多個(gè)線程組成。那么CPU,內(nèi)存,硬盤(pán),網(wǎng)絡(luò)這些硬件層面資源是怎么合理分配到我們軟件的各個(gè)進(jìn)程中呢?這就是內(nèi)核幫助我們完成的事情,我們并不關(guān)心我們?cè)O(shè)備上的應(yīng)用在哪里執(zhí)行,如何分配資源,內(nèi)核會(huì)完成這些事情。我們?nèi)粘Ec軟件交互,而內(nèi)核會(huì)幫助我們完成軟件和硬件的交互。

▍OpenHarmony內(nèi)核明白了什么是內(nèi)核后,我們來(lái)看看OpenHarmony的內(nèi)核是怎么樣設(shè)計(jì)的吧。OpenHarmony采用的是多內(nèi)核設(shè)計(jì) 有基于Linux內(nèi)核的標(biāo)準(zhǔn)系統(tǒng),有基于LiteOS-A的小型系統(tǒng),也有基于LiteOS-M的輕量系統(tǒng)。他們分別適配不同的設(shè)備,比如說(shuō)智能手表就是輕量級(jí)別的,智能汽車(chē)就是標(biāo)準(zhǔn)級(jí)別的等等。本篇并不介紹標(biāo)準(zhǔn)系統(tǒng)和小型系統(tǒng),輕量系統(tǒng)更加適合初學(xué)者。▍LiteOS-M內(nèi)核

下面是一張LiteOS-M的架構(gòu)圖

5fd28a18-ebd1-11ee-9118-92fbcf53809c.png

下面重點(diǎn)介紹KAL抽象層 和 基礎(chǔ)內(nèi)核的操作

KAL抽象層

相信大家還是會(huì)有疑惑,什么是KAL抽象層?Kernel Abstraction Layer在剛剛的內(nèi)核中我們提到了,內(nèi)核主要完成的是軟件與硬件的交互,他會(huì)給應(yīng)用層提供統(tǒng)一的規(guī)范接口,而KAL抽象層正是內(nèi)核對(duì)應(yīng)用層提供的接口集合。應(yīng)用程序可以通過(guò)KAL抽象層完成對(duì)硬件的控制交互。抽象層是因?yàn)樗[藏了與硬件接口具體的交互邏輯,開(kāi)發(fā)人員只需要關(guān)心如何操作硬件,而無(wú)需關(guān)心硬件底層的細(xì)節(jié),大大提高了可移植性和維護(hù)性。以筆者的角度去看,KAL簡(jiǎn)單來(lái)說(shuō)就是一堆接口,幫助你去操控硬件。CMSIS與POSIX就是具有統(tǒng)一規(guī)范的一些接口。通過(guò)他們我們就可以去控制一些基礎(chǔ)的內(nèi)核,線程,軟件定時(shí)器,互斥鎖,信號(hào)量等等。概念就先簡(jiǎn)單介紹這么多,感興趣的伙伴們可以上官網(wǎng)查看更多的關(guān)于OpenHarmony內(nèi)核的信息。下面筆者會(huì)帶著大家編碼操作,從實(shí)際去體會(huì)內(nèi)核編程。

內(nèi)核編程

▍線程管理

在管理線程前,我們需要了解線程,線程是調(diào)度的基本單位,具有獨(dú)立的??臻g和寄存器上下文,相比與進(jìn)程,他是輕量的。舉一個(gè)實(shí)際的例子,動(dòng)物園賣(mài)票。

對(duì)于動(dòng)物園賣(mài)票這件事本身而言是一個(gè)進(jìn)程,而每一個(gè)買(mǎi)票的人可以看作一個(gè)線程,在多個(gè)售票口處,我們并發(fā)執(zhí)行,并行計(jì)算,共同消費(fèi)動(dòng)物園的門(mén)票,像享受共同的內(nèi)存資源空間一樣。為什么要線程管理呢?你我都希望買(mǎi)到票,但是票有限,我們都不希望看到售票廳一篇混亂,因此對(duì)線程進(jìn)行管理是非常重要的一件事情。

任務(wù)

創(chuàng)建一個(gè)線程,每間隔0.1秒,輸出“Hello,OpenHarmony”,1秒后終止線程。

操作

回憶第一個(gè)hello.c的例子我們要編寫(xiě)的程序樣例就在源碼根目錄下的:applications/sample/wifi-iot/app/下面將具體演示如何編寫(xiě)程序樣例。1.新建樣例目錄applications/sample/wifi-iot/app/thread_demo2.新建源文件和gn文件applications/sample/wifi-iot/app/thread_demo/singleThread.capplications/sample/wifi-iot/app/thread_demo/BUILD.gn

5fe07f74-ebd1-11ee-9118-92fbcf53809c.png

3.編寫(xiě)源碼注意:我們需要使用到cmsis_os2.h這個(gè)庫(kù),請(qǐng)伙伴們按照筆者介紹的方法把includePath修改好。問(wèn)題一:怎么創(chuàng)建線程?

typedefstruct{
/**Threadname*/
constchar*name;
/**Threadattributebits*/
uint32_tattr_bits;
/**Memoryforthethreadcontrolblock*/
void*cb_mem;
/**Sizeofthememoryforthethreadcontrolblock*/
uint32_tcb_size;
/**Memoryforthethreadstack*/
void*stack_mem;
/**Sizeofthethreadstack*/
uint32_tstack_size;
/**Threadpriority*/
osPriority_tpriority;
/**TrustZonemoduleofthethread*/
TZ_ModuleId_ttz_module;
/**Reserved*/
uint32_treserved;
}osThreadAttr_t;

這是線程的結(jié)構(gòu)體,它具有以下屬性:

  • name:線程的名稱(chēng)。
  • attr_bits:線程屬性位。
  • cb_mem:線程控制塊的內(nèi)存地址。
  • cb_size:線程控制塊的內(nèi)存大小。
  • stack_mem:線程棧的內(nèi)存地址。
  • stack_size:線程棧的大小。
  • priority:線程的優(yōu)先級(jí)。
  • tz_module:線程所屬的TrustZone模塊。
  • reserved:保留字段。

問(wèn)題二:怎么把線程啟動(dòng)起來(lái)呢?

osThreadId_tosThreadNew(osThreadFunc_tfunc,void*argument,constosThreadAttr_t*attr);

這是創(chuàng)建線程的接口函數(shù),他有三個(gè)參數(shù),一個(gè)返回值,我們來(lái)逐個(gè)解析func:是線程的回調(diào)函數(shù),你創(chuàng)建的這個(gè)線程會(huì)執(zhí)行這段函數(shù)的內(nèi)容。arguments:線程回調(diào)函數(shù)的參數(shù)。attr:線程的屬性,也就是我們之前創(chuàng)建的線程返回值:線程的id 如果id不為空則說(shuō)明成功。問(wèn)題三:怎么終止線程呢?

osStatus_tosThreadTerminate(osThreadId_tthread_id);

顯然我們只要傳入線程的id就會(huì)讓該線程終止,返回值是一個(gè)狀態(tài)碼,下面給出全部的狀態(tài)碼

typedefenum{
/**Operationcompletedsuccessfully*/
osOK= 0,
/**Unspecifiederror*/
osError=-1,
/**Timeout*/
osErrorTimeout=-2,
/**Resourceerror*/
osErrorResource=-3,
/**Incorrectparameter*/
osErrorParameter=-4,
/**Insufficientmemory*/
osErrorNoMemory=-5,
/**Serviceinterruption*/
osErrorISR=-6,
/**Reserved.Itisusedtopreventthecompilerfromoptimizingenumerations.*/
osStatusReserved=0x7FFFFFFF
}osStatus_t;

回調(diào)函數(shù)怎么寫(xiě)?當(dāng)然是結(jié)合我們的任務(wù),每間隔0.1秒,輸出“Hello,OpenHarmony”,1秒后終止。講到這里,代碼的整體邏輯是不是就清晰了很多,直接上完整代碼。

#include
#include"ohos_init.h"
//CMSIS
#include"cmsis_os2.h"
//POSIX
#include

//線程回調(diào)函數(shù)
voidprintThread(void*args){
(void)args;
while(1){
printf("Hello,OpenHarmony!\r\n");
//休眠0.1秒
osDelay(10);
}
}

voidthreadTest(void){
//創(chuàng)建線程
osThreadAttr_tattr;
attr.name="mainThread";
//線程
attr.cb_mem=NULL;
attr.cb_size=0U;
attr.stack_mem=NULL;
attr.stack_size=1024;
attr.priority=osPriorityNormal;

//將線程啟動(dòng)
osThreadId_ttid=osThreadNew((osThreadFunc_t)printThread,NULL,&attr);
if(tid==NULL){
printf("[ThreadTest]FailedtocreateprintThread!\r\n");
}

//休眠5秒
osDelay(500);
//終止線程
osStatus_tstatus=osThreadTerminate(tid);
printf("[ThreadTest]printThreadstop,status=%d.\r\n",status);

}

APP_FEATURE_INIT(threadTest);

4.編寫(xiě)gn文件

static_library("thread_demo"){
sources=[
"singleThread.c"
]
include_dirs=[
"http://commonlibrary/utils_lite/include",
"http://device/soc/hisilicon/hi3861v100/hi3861_adapter/kal/cmsis"
]
}

5.編寫(xiě)app下的gn文件5fe8d3fe-ebd1-11ee-9118-92fbcf53809c.png

注意的是,這次的寫(xiě)法與上次不同,是因?yàn)楣P者的樣例文件名和靜態(tài)模塊的名字是一樣的就可以簡(jiǎn)寫(xiě)。

執(zhí)行效果

5ffaf610-ebd1-11ee-9118-92fbcf53809c.png▍多線程的封裝

在處理業(yè)務(wù)的時(shí)候,我們一般是多線程的背景,下面筆者將創(chuàng)建線程函數(shù)封裝起來(lái),方便大家創(chuàng)建多線程

osThreadId_tnewThread(char*name,osThreadFunc_tfunc,void*arg){
//定義線程和屬性
osThreadAttr_tattr={
name,0,NULL,0,NULL,1024,osPriorityNormal,0,0
};
//創(chuàng)建線程
osThreadId_ttid=osThreadNew(func,arg,&attr);
if(tid==NULL){
printf("[newThread]osThreadNew(%s)failed.\r\n",name);
}
returntid;
}

線程部分先體會(huì)到這里,想要探索更過(guò)線程相關(guān)的API,筆者這里提供了API網(wǎng)站,供大家參考學(xué)習(xí)。

CMSIS_OS2 Thread API:https://arm-software.github.io/CMSIS_5/RTOS2/html/os2MigrationFunctions.html#mig_threadMgmt

軟件定時(shí)器

下面我們介紹軟件定時(shí)器,老樣子我們先來(lái)介紹以下軟件定時(shí)器。軟件定時(shí)器是一種在軟件層面上實(shí)現(xiàn)的計(jì)時(shí)器機(jī)制,用于在特定的時(shí)間間隔內(nèi)執(zhí)行特定的任務(wù)或觸發(fā)特定的事件。它不依賴(lài)于硬件定時(shí)器,而是通過(guò)軟件編程的方式實(shí)現(xiàn)。舉一個(gè)例子,手機(jī)應(yīng)用。

當(dāng)你使用手機(jī)上的某個(gè)應(yīng)用時(shí),你可能會(huì)注意到,如果你在一段時(shí)間內(nèi)沒(méi)有進(jìn)行任何操作,應(yīng)用程序會(huì)自動(dòng)斷開(kāi)連接并要求你重新登錄。這是為了保護(hù)你的賬號(hào)安全并釋放服務(wù)器資源。類(lèi)似的設(shè)定都是有軟件定時(shí)器實(shí)現(xiàn)的,下面進(jìn)行實(shí)際操作,讓大家體會(huì)一下軟件定時(shí)器。

任務(wù)

創(chuàng)建一個(gè)軟件定時(shí)器,用來(lái)模擬上述手機(jī)應(yīng)用的例子。為了方便理解,假設(shè)從此刻開(kāi)始,我們不對(duì)手機(jī)做任何操作,也就是說(shuō),我們的回調(diào)函數(shù)只需要單純的計(jì)算應(yīng)用不被操作的時(shí)常即可。

操作

1.新建樣例目錄applications/sample/wifi-iot/app/thread_demo2.新建源文件和gn文件applications/sample/wifi-iot/app/thread_demo/singleThread.capplications/sample/wifi-iot/app/thread_demo/BUILD.gn3.編寫(xiě)源碼創(chuàng)建軟件定時(shí)器

osTimerId_tosTimerNew(osTimerFunc_tfunc,osTimerType_ttype,void*argument,constosTimerAttr_t*attr);

func: 軟件定時(shí)器的回調(diào)函數(shù)type:軟件定時(shí)器的種類(lèi)argument:軟件定時(shí)器回調(diào)函數(shù)的參數(shù)attr:軟件定時(shí)器的屬性返回值:返回軟件定時(shí)器的id, id為空則說(shuō)明軟件定時(shí)器失敗

typedefenum{
/**One-shottimer*/
osTimerOnce=0,
/**Repeatingtimer*/
osTimerPeriodic=1
}osTimerType_t;

軟件定時(shí)器的種類(lèi)有兩個(gè),分為一次性定時(shí)器和周期性定時(shí)器,一次性在執(zhí)行完回調(diào)函數(shù)后就會(huì)停止計(jì)數(shù),而周期性定時(shí)器會(huì)重復(fù)觸發(fā),每次觸發(fā)重新計(jì)時(shí)。根據(jù)不同的需求我們可以選擇使用不同的軟件定時(shí)器。啟動(dòng)軟件定時(shí)器

osStatus_tosTimerStart(osTimerId_ttimer_id,uint32_tticks);

timer_id:軟件定時(shí)器的參數(shù),指定要啟動(dòng)哪個(gè)軟件定時(shí)器ticks:等待多少個(gè)ticks執(zhí)行回調(diào)函數(shù),在Hi3861中 100個(gè)ticks為1秒返回值:軟件定時(shí)器的狀態(tài)碼,在線程部分已經(jīng)展示給大家了全部的狀態(tài)碼停止定時(shí)器

osStatus_tosTimerStop(osTimerId_ttimer_id);

這個(gè)函數(shù)很簡(jiǎn)單,只需要傳軟件定時(shí)器的id,即可停止軟件計(jì)時(shí)器,并且返回他的狀態(tài)碼刪除定時(shí)器

osStatus_tosTimerDelete(osTimerId_ttimer_id);

刪除和停止類(lèi)似,就不多說(shuō)明了。下面是源代碼

#include
#include"ohos_init.h"
//CMSIS
#include"cmsis_os2.h"
//POSIX
#include

//為操作軟件的時(shí)間
staticinttimes=0;

//軟件定時(shí)器回調(diào)函數(shù)
voidtimerFunction(void){
times++;
printf("[TimerTest]TimerisRunning,times=%d.\r\n",times);
}

//主函數(shù)
voidtimerMain(void){
//創(chuàng)建軟件定時(shí)器
osTimerId_ttid=osTimerNew(timerFunction,osTimerPeriodic,NULL,NULL);
if(tid==NULL){
printf("[TimerTest]Failedtocreateatimer!\r\n");
return;
}else{
printf("[TimerTest]Createatimersuccess!\r\n");
}
//啟動(dòng)軟件定時(shí)器,每1秒執(zhí)行一次回調(diào)函數(shù)
osStatus_tstatus=osTimerStart(tid,100);

//當(dāng)超過(guò)三個(gè)周期位操作軟件時(shí),關(guān)閉軟件
while(times<=?3){
osDelay(100);
}
//停止軟件定時(shí)器
status=osTimerStop(tid);
//刪除軟件定時(shí)器
status=osTimerDelete(tid);
printf("[TimerTest]TimeOut!\r\n");
}

voidTimerTest(void){
//創(chuàng)建測(cè)試線程
osThreadAttr_tattr;
attr.name="timerMain";
attr.attr_bits=0U;
attr.cb_mem=NULL;
attr.cb_size=0U;
attr.stack_mem=NULL;
attr.stack_size=0U;
attr.priority=osPriorityNormal;

//啟動(dòng)測(cè)試線程
osThreadId_ttid=osThreadNew((osThreadFunc_t)timerMain,NULL,&attr);
if(tid==NULL){
printf("[TimerTest]FailedtocreatedtimerMain!\r\n");
}
}

APP_FEATURE_INIT(TimerTest);

4.編寫(xiě)gn文件

static_library("timer_demo"){
sources=[
"timer.c"
]
include_dirs=[
"http://commonlibrary/utils_lite/include",
"http://device/soc/hisilicon/hi3861v100/hi3861_adapter/kal/cmsis"
]
}

5.編寫(xiě)app下的gn文件603c0b14-ebd1-11ee-9118-92fbcf53809c.png

執(zhí)行效果

603c0b14-ebd1-11ee-9118-92fbcf53809c.png軟件定時(shí)器的API相對(duì)較少,這里還是提供所有的軟件定時(shí)器APICMSIS_OS2 Timer API:https://arm-software.github.io/CMSIS_5/RTOS2/html/os2MigrationFunctions.html#mig_timer▍互斥鎖線程的狀態(tài)
在介紹互斥鎖之前,我們有必要去了解一下線程的狀態(tài),或者說(shuō)線程的生命周期。避免伙伴們因?yàn)椴粔蚴煜ぞ€程而對(duì)這個(gè)互斥鎖的概念感到困難。首先介紹一下線程的幾個(gè)狀態(tài),他們分別有:

  • 創(chuàng)建

創(chuàng)建線程,在OpenHarmony的源碼中,線程的屬性被封裝成了一個(gè)名為”osThreadAttr_t“的結(jié)構(gòu)體

typedefstruct{
constchar*name;
uint32_tattr_bits;
void*cb_mem;
uint32_tcb_size;
void*stack_mem;
uint32_tstack_size;
osPriority_tpriority;
TZ_ModuleId_ttz_module;
uint32_treserved;
}osThreadAttr_t;

  • name:線程的名稱(chēng)。
  • attr_bits:線程屬性位。
  • cb_mem:線程控制塊的內(nèi)存地址。
  • cb_size:線程控制塊的內(nèi)存大小。
  • stack_mem:線程棧的內(nèi)存地址。
  • stack_size:線程棧的大小。
  • priority:線程的優(yōu)先級(jí)。
  • tz_module:線程所屬的TrustZone模塊。
  • reserved:保留字段。

當(dāng)我們創(chuàng)建一個(gè)線程的時(shí)候,系統(tǒng)就會(huì)為該線程分配所需要的資源,將線程加入到系統(tǒng)的線程調(diào)度隊(duì)列中,此時(shí)線程已經(jīng)處在就緒狀態(tài)了。

  • 就緒

線程一旦被創(chuàng)建,就會(huì)進(jìn)入就緒狀態(tài),他表示我們完成的線程的創(chuàng)建(線程相關(guān)屬性的初始化),但是并未運(yùn)行,線程正在等待操作系統(tǒng)調(diào)度程序,將其調(diào)度運(yùn)行起來(lái)。

  • 運(yùn)行

之前我們介紹了一個(gè)關(guān)于線程的API,他可以將就緒狀態(tài)的線程加入到活躍線程組

osThreadId_tosThreadNew(osThreadFunc_tfunc,void*argument,constosThreadAttr_t*attr);

此時(shí)的線程將會(huì)占用部分cpu資源執(zhí)行他的程序,直到程序結(jié)束,或者線程被阻塞,cpu被搶占等。

  • 阻塞

線程阻塞,可以理解為線程無(wú)法繼續(xù)往下執(zhí)行,但時(shí)線程執(zhí)行的程序不會(huì)直接退出,他會(huì)進(jìn)入到等待的狀態(tài),直到相關(guān)資源被釋放,線程可以繼續(xù)執(zhí)行。

  • 終止

上篇我們介紹了線程終止的API

sStatus_tstatus=osThreadTerminate(osThreadId_ttid);

此時(shí)線程完成了自己的代碼邏輯,我們方可主動(dòng)調(diào)用該API徹底刪除這個(gè)線程。當(dāng)然如果具體細(xì)分,其實(shí)不止這五個(gè)狀態(tài),但是了解了這五個(gè)狀態(tài)就足夠了。下面我們來(lái)聊聊什么是互斥鎖。互斥鎖簡(jiǎn)介

互斥鎖的應(yīng)用場(chǎng)景時(shí)處理多線程,資源訪問(wèn)的問(wèn)題。這里還是給大家舉一個(gè)例子:動(dòng)物園賣(mài)票。

在我們的程序設(shè)計(jì)中,往往會(huì)有共有資源,每個(gè)線程都可以進(jìn)來(lái)訪問(wèn)這些資源。這里的共有資源就是我們的門(mén)票,一個(gè)售票口就是一個(gè)線程,當(dāng)有人來(lái)窗口買(mǎi)票,我們的門(mén)票就會(huì)減少一張。當(dāng)然一個(gè)動(dòng)物園的流量時(shí)巨大的,我們不能只設(shè)立一個(gè)售票口,這樣的效率是很低的。京東淘寶搶購(gòu)秒殺也一樣,我們必須設(shè)立多個(gè)窗口,在同一時(shí)刻為多個(gè)人處理業(yè)務(wù)。多線程解決了效率問(wèn)題但也帶來(lái)了安全隱患。我們假設(shè)一個(gè)這樣的場(chǎng)景,動(dòng)物園僅剩一張門(mén)票,但是有兩個(gè)在不同的窗口同時(shí)付了錢(qián),當(dāng)售票員為他們拿票的時(shí)候就會(huì)發(fā)現(xiàn),少了一張票,兩個(gè)人都付了錢(qián)都想要那張票,就陷入了一個(gè)死局,無(wú)奈動(dòng)物園只能讓他們都進(jìn)去。但是在程序中體現(xiàn)的可能就是一個(gè)bug,動(dòng)物園的門(mén)票剩余數(shù)為:-1。

if(count>0){
count--;
}

售票的邏輯很簡(jiǎn)單,只要票數(shù)大于零,還有票能賣(mài),那就在此基礎(chǔ)上減掉一。問(wèn)題就在于,兩個(gè)線程同時(shí)在count = 1的時(shí)候通過(guò)了if判斷,都執(zhí)行的count--;那么就會(huì)出現(xiàn)了count = -1,也就是票數(shù)為負(fù) 的bug結(jié)果。

互斥鎖的出現(xiàn)就很好地解決了一個(gè)問(wèn)題,他能夠阻止上面兩個(gè)線程同時(shí)訪問(wèn)資源的同步行為,也就是說(shuō)當(dāng)一個(gè)線程進(jìn)入這個(gè)if語(yǔ)句后,別的線程都不能進(jìn)入。形象起來(lái)說(shuō),就像對(duì)這段代碼加了鎖,只有有鑰匙的線程才能夠訪問(wèn)它。6061b058-ebd1-11ee-9118-92fbcf53809c.png

互斥鎖API

通過(guò)對(duì)幾個(gè)API的介紹,讓大家知道怎么為一段代碼加上互斥鎖

1.創(chuàng)建互斥鎖與線程的定義一樣,互斥鎖也封裝成了一個(gè)結(jié)構(gòu)體

typedefstruct{
/**Mutexname*/
constchar*name;
/**Reservedattributebits*/
uint32_tattr_bits;
/**Memoryforthemutexcontrolblock*/
void*cb_mem;
/**Sizeofthememoryforthemutexcontrolblock*/
uint32_tcb_size;
}osMutexAttr_t;

  • name:互斥鎖的名稱(chēng)
  • attr_bits:保留的屬性位
  • cb_mem:互斥鎖控制塊的內(nèi)存
  • cb_size:互斥鎖控制塊內(nèi)存的大小

2.獲取互斥鎖的id

osMutexId_tosMutexNew(constosMutexAttr_t*attr);

將我們上面定義的互斥鎖屬性傳入函數(shù),返回互斥鎖的id3.線程獲取互斥鎖

osStatus_tosMutexAcquire(osMutexId_tmutex_id,uint32_ttimeout);

傳入互斥鎖id,設(shè)置我們的延遲時(shí)間,當(dāng)線程獲取到我們的互斥鎖時(shí),返回的狀態(tài)是osOK。

下面是全部的狀態(tài)碼

typedefenum{
/**Operationcompletedsuccessfully*/
osOK= 0,
/**Unspecifiederror*/
osError=-1,
/**Timeout*/
osErrorTimeout=-2,
/**Resourceerror*/
osErrorResource=-3,
/**Incorrectparameter*/
osErrorParameter=-4,
/**Insufficientmemory*/
osErrorNoMemory=-5,
/**Serviceinterruption*/
osErrorISR=-6,
/**Reserved.Itisusedtopreventthecompilerfromoptimizingenumerations.*/
osStatusReserved=0x7FFFFFFF
}osStatus_t;

4.釋放鎖

osStatus_tosMutexRelease(osMutexId_tmutex_id);

當(dāng)我們的線程執(zhí)行完業(yè)務(wù)后需要把鎖釋放出來(lái),讓別的線程獲取鎖,執(zhí)行業(yè)務(wù)。當(dāng)然這個(gè)過(guò)程是線程之間的競(jìng)爭(zhēng),一個(gè)線程可能一直得不到鎖,一個(gè)線程也可能剛釋放鎖又獲得鎖,我們可以添加休眠操作,提高鎖在各個(gè)線程間的分配。

其他API請(qǐng)參考:Mutex API:https://arm-software.github.io/CMSIS_5/RTOS2/html/os2MigrationFunctions.html#mig_mutex操作1.新建樣例目錄applications/sample/wifi-iot/app/mutex_demo2.新建源文件和gn文件applications/sample/wifi-iot/app/mutex_demo/mutex.capplications/sample/wifi-iot/app/mutex_demo/BUILD.gn

606aadb6-ebd1-11ee-9118-92fbcf53809c.png

3.源碼編寫(xiě)因?yàn)橐呀?jīng)介紹了主要的API,這里就直接給伙伴們上源碼了。

#include
#include
#include"ohos_init.h"
#include"cmsis_os2.h"

//模擬動(dòng)物園門(mén)票數(shù)
staticintcount=100;

//售票業(yè)務(wù)線程
voidoutThread(void*args){
//獲取互斥鎖
osMutexId_t*mid=(osMutexId_t*)args;
//每個(gè)線程都在不停地買(mǎi)票
while(1){
//獲取鎖,進(jìn)入業(yè)務(wù)流程
if(osMutexAcquire(*mid,100)==osOK){
if(count>0){
count--;
//設(shè)置提示信息
printf("[MutexTest]Thread%sgetavalue,thelessis%d.\r\n",osThreadGetName(osThreadGetId()),count);
}else{
//告知這些線程已經(jīng)沒(méi)有門(mén)票賣(mài)了,線程結(jié)束
printf("[MutexTest]Thevalueisout!\r\n");
osThreadTerminate(osThreadGetId());
}
}
//釋放鎖
osMutexRelease(*mid);

osDelay(5);
}
}
//創(chuàng)建線程封裝
osThreadId_tcreateThreads(char*name,osThreadFunc_tfunc,void*args){
osThreadAttr_tattr={
name,0,NULL,0,NULL,1024,osPriorityNormal,0,0
};
osThreadId_ttid=osThreadNew(func,args,&attr);
returntid;
}

//主函數(shù)實(shí)現(xiàn)多線程的創(chuàng)建,執(zhí)行買(mǎi)票業(yè)務(wù)
voidmutexMain(void){
//創(chuàng)建互斥鎖
osMutexAttr_tattr={0};

//獲取互斥鎖的id
osMutexId_tmid=osMutexNew(&attr);

if(mid==NULL){
printf("[MutexTest]Failedtocreateamutex!\r\n");
}

//創(chuàng)建多線程
osThreadId_ttid1=createThreads("Thread_1",(osThreadFunc_t)outThread,&mid);
osThreadId_ttid2=createThreads("Thread_2",(osThreadFunc_t)outThread,&mid);
osThreadId_ttid3=createThreads("Thread_3",(osThreadFunc_t)outThread,&mid);

osDelay(1000);

}

//測(cè)試線程
voidMainTest(void){
osThreadId_ttid=createThreads("MainTest",(osThreadFunc_t)mutexMain,NULL);
}

APP_FEATURE_INIT(MainTest);

4.編寫(xiě)gn文件

static_library("mutex_demo"){
sources = [
"mutex.c"
]
include_dirs = [
"http://commonlibrary/utils_lite/include",
"http://device/soc/hisilicon/hi3861v100/hi3861_adapter/kal/cmsis"
]
}

5.編寫(xiě)app目錄下的gn文件607d4714-ebd1-11ee-9118-92fbcf53809c.png

結(jié)果展示

6090d1da-ebd1-11ee-9118-92fbcf53809c.png可能有的伙伴們看到這里不太清晰,會(huì)覺(jué)得這段代碼真的上鎖了嗎

if(osMutexAcquire(*mid,100)==osOK){
if(count>0){
count--;
printf("[MutexTest]Thread%sgetavalue,thelessis%d.\r\n",osThreadGetName(osThreadGetId()),count);
}else{
printf("[MutexTest]Thevalueisout!\r\n");
osThreadTerminate(osThreadGetId());
}
}

那么我們可以不使用互斥鎖再次執(zhí)行這段代碼60aa5c36-ebd1-11ee-9118-92fbcf53809c.png

結(jié)果展示如下:

60bda28c-ebd1-11ee-9118-92fbcf53809c.png

注:這里筆者還另外多加了3個(gè)線程,一共六個(gè)線程,可以看出來(lái)控制臺(tái)的輸出很混亂,當(dāng)一個(gè)線程在執(zhí)行輸出指令時(shí),另一個(gè)線程也插了進(jìn)來(lái)執(zhí)行輸出指令所造成的,再看票數(shù),也是出現(xiàn)了明顯的問(wèn)題。因此互斥鎖在處理多線程問(wèn)題時(shí),起到了非常重要的作用。可能有伙伴好奇,怎么沒(méi)有負(fù)數(shù)票的出現(xiàn),筆者作為學(xué)習(xí)者,代碼能力也有限,可能寫(xiě)出來(lái)的案例并不是非常精確,僅供參考。▍信號(hào)量

對(duì)大部分初學(xué)者而言,這又是一個(gè)新名詞,什么是信號(hào)量?其實(shí)他跟我們上篇介紹的互斥鎖很像?;コ怄i是在多線程中允許一個(gè)線程訪問(wèn)資源,信號(hào)量是在多線程中允許多個(gè)線程訪問(wèn)資源。

60cd7ac2-ebd1-11ee-9118-92fbcf53809c.png初學(xué)者一定會(huì)感到困惑,為了解決多線程訪問(wèn)資源的風(fēng)險(xiǎn)我們限制只能有一個(gè)線程在某一時(shí)刻訪問(wèn)資源,現(xiàn)在這個(gè)信號(hào)量怎么有允許多個(gè)線程訪問(wèn)資源呢。筆者剛開(kāi)始也比較困惑,結(jié)合一些案例理解后,也是明白了這樣的設(shè)計(jì)初衷。實(shí)際上,信號(hào)量,互斥鎖本就是兩種不同的多形成同步運(yùn)行機(jī)制,在特定的應(yīng)用場(chǎng)景下,有特定的需求,而信號(hào)量,互斥鎖可以滿(mǎn)足不同的需求,具體是什么需求呢,舉個(gè)例子給大家。賣(mài)票,我們的確需要互斥鎖解決多線程可能帶來(lái)的錯(cuò)誤,那么如果是驗(yàn)票呢,為了提高效率,我們開(kāi)設(shè)多個(gè)入口同時(shí)驗(yàn)票且不會(huì)發(fā)生沖突,信號(hào)量就做到了限制線程數(shù)量訪問(wèn)資源的作用。如果我們不限制并發(fā)的數(shù)量,我們的程序占用資源可能會(huì)非常大,甚至崩潰,就像檢票的入口沒(méi)有被明確入口數(shù)量一樣,門(mén)口的人們會(huì)亂成一片。

信號(hào)量API

1.創(chuàng)建信號(hào)量

osSemaphoreId_tosSemaphoreNew(uint32_tmax_count,uint32_tinitial_count,constosSemaphoreAttr_t*attr);

參數(shù)解釋?zhuān)鹤畲笕萘苛?,初始容納量,信號(hào)量屬性最大容納量說(shuō)明了,我們的資源最大能被多少線程訪問(wèn)初始容納量說(shuō)明了,我們當(dāng)前實(shí)際能有多少線程訪問(wèn)資源,因?yàn)橐粋€(gè)信號(hào)對(duì)應(yīng)一個(gè)線程的許可。返回值:信號(hào)量的id2.獲取信號(hào)量

osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout);

參數(shù)解釋?zhuān)盒盘?hào)量的id,等待時(shí)長(zhǎng)返回值:狀態(tài)碼 (介紹很多遍了,就不說(shuō)明了)我們往往會(huì)在timoeout處設(shè)置為 oswaitForever

#defineosWaitForever0xFFFFFFFFU

這樣我們的線程就會(huì)一直等,直到有信號(hào)量空出來(lái)被他獲取,才執(zhí)行后續(xù)的代碼。3.釋放信號(hào)量

osStatus_tosSemaphoreRelease(osSemaphoreId_tsemaphore_id);

很簡(jiǎn)單,傳入信號(hào)量的id,就可以釋放一個(gè)信號(hào)量出來(lái)。其他的API請(qǐng)參考:Semaphore API:https://arm-software.github.io/CMSIS_5/RTOS2/html/os2MigrationFunctions.html#mig_sem

任務(wù)

有4個(gè)售票窗,2個(gè)檢票口,每次會(huì)有4個(gè)人來(lái)買(mǎi)票,然后去檢票,用互斥鎖控制購(gòu)票,信號(hào)量控制檢票。

操作

1.新建樣例目錄applications/sample/wifi-iot/app/semaphore_demo2.新建源文件和gn文件applications/sample/wifi-iot/app/semaphore_demo/semaphore.capplications/sample/wifi-iot/app/semaphore_demo/BUILD.gn

60d5972a-ebd1-11ee-9118-92fbcf53809c.png

3.源碼編寫(xiě)

直接上源碼了

#include
#include
#include"ohos_init.h"
#include"cmsis_os2.h"

//售票口4
#defineOUT_NUM4
//檢票口2
#defineIN_NUM2

//信號(hào)量
osSemaphoreId_tsid;

//待檢票人數(shù)
staticintpeople=0;

//售票業(yè)務(wù)
voidoutThread(void*args){
//獲取互斥鎖
osMutexId_t*mid=(osMutexId_t*)args;

while(1){
if(osMutexAcquire(*mid,100)==osOK){
//賣(mài)一張票,帶檢票的人數(shù)就會(huì)加一位
people++;
printf("[SEMAPHORETEST]out,people:%d.\r\n",people);
}
osMutexRelease(*mid);
osDelay(50);
}
}

//檢票業(yè)務(wù)
voidinThread(void*args){
//獲取信號(hào)量
osSemaphoreAcquire(sid,osWaitForever);
while(1){
if(people>0){
people--;
printf("[SEMAPHORETEST]in,people:%d.\r\n",people);
}
osSemaphoreRelease(sid);
osDelay(100);
}
}

//創(chuàng)建線程封裝
osThreadId_tcreateThreads(char*name,osThreadFunc_tfunc,void*args){
osThreadAttr_tattr={
name,0,NULL,0,NULL,1024*2,osPriorityNormal,0,0
};
osThreadId_ttid=osThreadNew(func,args,&attr);
returntid;
}

//主線程
voidSemaphoreMain(void){
//創(chuàng)建信號(hào)量
sid=osSemaphoreNew(IN_NUM,IN_NUM,NULL);

//創(chuàng)建互斥鎖
osMutexAttr_tattr={0};

//獲取互斥鎖的id
osMutexId_tmid=osMutexNew(&attr);

//創(chuàng)建售票線程
for(inti=0;icreateThreads("",(osThreadFunc_t)outThread,&mid);
}

//創(chuàng)建檢票線程
for(inti=0;icreateThreads("",(osThreadFunc_t)inThread,NULL);
}
}

//測(cè)試函數(shù)
voidMainTest(){
createThreads("MainTest",(osThreadFunc_t)SemaphoreMain,NULL);
}

APP_FEATURE_INIT(MainTest);

4.編寫(xiě)gn文件

static_library("semaphore_demo"){
sources = [
"semaphore.c"
]
include_dirs = [
"http://utils/native/lite/include",
]
}

5.編寫(xiě)app目錄下的gn文件60e27ca6-ebd1-11ee-9118-92fbcf53809c.png

結(jié)果展示

60fdaee0-ebd1-11ee-9118-92fbcf53809c.png大家可以加長(zhǎng)檢票業(yè)務(wù)的休眠時(shí)間,我們的檢票口是兩個(gè),in的業(yè)務(wù)一定是兩個(gè)一起執(zhí)行的??傊盘?hào)量和互斥鎖是多線程管理中的重點(diǎn),大家一定要好好體會(huì)他們的作用和區(qū)別。▍消息隊(duì)列本篇的最后我們來(lái)介紹消息隊(duì)列。隊(duì)列相信大部分朋友都不陌生,是一種基本且常用的數(shù)據(jù)結(jié)構(gòu),這里筆者就不介紹隊(duì)列的相關(guān)信息了。那么什么是消息隊(duì)列呢?有什么應(yīng)用場(chǎng)景呢。
6115bc92-ebd1-11ee-9118-92fbcf53809c.png消息隊(duì)列也是多線程,高并發(fā)中的處理方式,大家可以理解為“同步入隊(duì),異步出隊(duì)”。老樣子從一個(gè)案例解釋?zhuān)W(wǎng)購(gòu)秒殺。在網(wǎng)購(gòu)秒殺時(shí),會(huì)有上萬(wàn)甚至上百萬(wàn)的流量涌入服務(wù)器,下單即可看作一個(gè)請(qǐng)求,向服務(wù)器請(qǐng)求獲取某個(gè)商品。服務(wù)器處理,生成買(mǎi)家的訂單號(hào)。當(dāng)然強(qiáng)大服務(wù)器的也無(wú)法在同一時(shí)刻支持如此多的請(qǐng)求,并且商品的數(shù)量也不足被所有人購(gòu)買(mǎi),這個(gè)時(shí)候,我們的消息隊(duì)列就會(huì)同步接受大家的請(qǐng)求,所有的請(qǐng)求都會(huì)被壓進(jìn)一個(gè)隊(duì)列中,服務(wù)器從隊(duì)列中依次獲取消息,確保不會(huì)因?yàn)橘Y源被占用而導(dǎo)致系統(tǒng)崩潰。6120f0bc-ebd1-11ee-9118-92fbcf53809c.png

#### 消息隊(duì)列API

1.創(chuàng)建消息隊(duì)列

osMessageQueueId_tosMessageQueueNew(uint32_tmsg_count,uint32_tmsg_size,constosMessageQueueAttr_t*attr);

參數(shù)說(shuō)明:

  • msg_count:消息隊(duì)列中的消息數(shù)量。
  • msg_size:消息隊(duì)列中每個(gè)消息的大小,通常我們的消息會(huì)用一個(gè)結(jié)構(gòu)體來(lái)自定義消息的內(nèi)容
  • attr:指向消息隊(duì)列屬性。

該函數(shù)的返回值是osMessageQueueId_t類(lèi)型,表示消息隊(duì)列的ID。如果創(chuàng)建消息隊(duì)列失敗,函數(shù)將返回NULL。2.向消息隊(duì)列加入消息

osStatus_tosMessageQueuePut(osMessageQueueId_tmq_id,constvoid*msg_ptr,uint8_tmsg_prio,uint32_ttimeout);

參數(shù)說(shuō)明:

  • mq_id:消息隊(duì)列的ID,通過(guò)調(diào)用osMessageQueueNew函數(shù)獲得。
  • msg_ptr:指向要放入消息隊(duì)列的消息緩沖區(qū)的指針,也就是我們將結(jié)構(gòu)體的指針轉(zhuǎn)遞給函數(shù)
  • msg_prio:消息的優(yōu)先級(jí)。
  • timeout:延時(shí),使用osWaitForever,線程就會(huì)一直等待直到隊(duì)列中有空余的位置。

該函數(shù)的返回值是osStatus_t類(lèi)型,表示函數(shù)執(zhí)行的結(jié)果。3.從消息隊(duì)列中接受消息

osStatus_tosMessageQueueGet(osMessageQueueId_tmq_id,void*msg_ptr,uint8_t*msg_prio,uint32_ttimeout);

參數(shù)說(shuō)明:

  • mq_id:消息隊(duì)列的ID,通過(guò)調(diào)用osMessageQueueNew函數(shù)獲得。
  • msg_ptr:指向存儲(chǔ)從消息隊(duì)列中獲取的消息的緩沖區(qū)的指針。
  • msg_prio:指向存儲(chǔ)從消息隊(duì)列中獲取的消息的優(yōu)先級(jí)的緩沖區(qū)的指針。
  • timeout:延時(shí),使用osWaitForever,線程就會(huì)一直等待直到隊(duì)列中有消息了。

該函數(shù)的返回值是osStatus_t類(lèi)型,表示函數(shù)執(zhí)行的結(jié)果。4.刪除消息隊(duì)列

osStatus_tosMessageQueueDelete(osMessageQueueId_tmq_id);

參數(shù)說(shuō)明:

  • mq_id:消息隊(duì)列的ID,通過(guò)調(diào)用osMessageQueueNew函數(shù)獲得。

該函數(shù)的返回值是osStatus_t類(lèi)型,表示函數(shù)執(zhí)行的結(jié)果。其他的API請(qǐng)參考:MessageQueue API:https://arm-software.github.io/CMSIS_5/RTOS2/html/os2MigrationFunctions.html#mig_msgQueue

任務(wù)

模擬搶購(gòu)秒殺,假設(shè)我們有10個(gè)線程,15個(gè)大小的消息隊(duì)列,5件商品。

操作

1.新建樣例目錄applications/sample/wifi-iot/app/queue_demo2.新建源文件和gn文件applications/sample/wifi-iot/app/queue_demo/queue.capplications/sample/wifi-iot/app/queue_demo/BUILD.gn

612b170e-ebd1-11ee-9118-92fbcf53809c.png

3.編寫(xiě)源碼

直接上源碼

#include
#include
#include"ohos_init.h"
#include"cmsis_os2.h"

//定義消息隊(duì)列的大小
#defineQUEUE_SIZE15

//定義請(qǐng)求數(shù)量
#defineREQ_SIZE10

//定義消息的結(jié)構(gòu)
typedefstruct{
osThreadId_ttid;
}message_queue;

//創(chuàng)建消息隊(duì)列id
osMessageQueueId_tqid;

//模擬發(fā)送業(yè)務(wù)
voidsendThread(void){
//定義一個(gè)消息結(jié)構(gòu)
message_queuesentry;
sentry.tid=osThreadGetId();

osDelay(100);

//消息入隊(duì)
osMessageQueuePut(qid,(constvoid*)&sentry,0,osWaitForever);

//設(shè)置提示信息
printf("[MESSAGEQUEUETEST]%dsendamessage.\r\n",sentry.tid);
}

//模擬處理業(yè)務(wù)
voidreceiverThread(void){
//定義一個(gè)消息結(jié)構(gòu)
message_queuerentry;
intless=5;
while(less>0){
osMessageQueueGet(qid,(void*)&rentry,NULL,osWaitForever);
less--;
printf("[MESSAGEQUEUETEST]%dgetaproduct,less=%d.\r\n",rentry.tid,less);
osDelay(5);
}
printf("[MESSAGEQUEUETEST]over!\r\n");
}

//創(chuàng)建線程封裝
osThreadId_tcreateThreads(char*name,osThreadFunc_tfunc,void*args){
osThreadAttr_tattr={
name,0,NULL,0,NULL,1024*2,osPriorityNormal,0,0
};
osThreadId_ttid=osThreadNew(func,args,&attr);
returntid;
}

//主線程
voidMessageQueueMain(void){
//創(chuàng)建一個(gè)消息隊(duì)列
qid=osMessageQueueNew(QUEUE_SIZE,sizeof(message_queue),NULL);

//創(chuàng)建發(fā)送線程
for(inti=0;icreateThreads("",(osThreadFunc_t)sendThread,NULL);
}
osDelay(5);

//創(chuàng)建接收線程
createThreads("",(osThreadFunc_t)receiverThread,NULL);

osDelay(500);

//刪除消息隊(duì)列
osMessageQueueDelete(qid);
}

//測(cè)試函數(shù)
voidMainTest(){
createThreads("MainTest",(osThreadFunc_t)MessageQueueMain,NULL);
}

APP_FEATURE_INIT(MainTest);

4.編寫(xiě)gn

static_library("queue_demo"){
sources=[
"queue.c",
]
include_dirs=[
"http://utils/native/lite/include",
]
}

5.編寫(xiě)app目錄下的gn

61322300-ebd1-11ee-9118-92fbcf53809c.png

結(jié)果展示

61467f6c-ebd1-11ee-9118-92fbcf53809c.png因?yàn)榫€程創(chuàng)建是循環(huán)創(chuàng)建的,先創(chuàng)建的線程就優(yōu)先發(fā)送了請(qǐng)求,可以看的出來(lái),前五個(gè)線程搶到了商品。如果線程可以同時(shí)發(fā)送請(qǐng)求,爭(zhēng)搶入隊(duì)的時(shí)機(jī),模擬將會(huì)更加準(zhǔn)確一些,這里只是簡(jiǎn)單的模擬。

結(jié)束語(yǔ)

至此內(nèi)核的基礎(chǔ)內(nèi)容就給伙伴們介紹完了,內(nèi)核作為一個(gè)系統(tǒng)的底層起到了相當(dāng)重要的作用,大家要好好體會(huì),希望能幫助到學(xué)習(xí)OpenHarmony的伙伴們。

聲明:本文內(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)投訴
  • 內(nèi)核
    +關(guān)注

    關(guān)注

    3

    文章

    1336

    瀏覽量

    40082
  • 開(kāi)發(fā)板
    +關(guān)注

    關(guān)注

    25

    文章

    4771

    瀏覽量

    96155
  • OpenHarmony
    +關(guān)注

    關(guān)注

    25

    文章

    3548

    瀏覽量

    15734
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    [HarmonyOS][鴻蒙專(zhuān)欄開(kāi)篇]快速入門(mén)OpenHarmony的LiteOS微內(nèi)核

    ://openharmony.gitee.com]倉(cāng)庫(kù)本專(zhuān)欄主要分析`OpenHarmony`內(nèi)核的相關(guān)代碼:Cortex-A系列處理器內(nèi)核:[kernel_liteos_a](htt
    發(fā)表于 09-14 19:40

    OpenHarmony LiteOS-A內(nèi)核介紹

    簡(jiǎn)介OpenHarmony LiteOS-A內(nèi)核是基于Huawei LiteOS內(nèi)核演進(jìn)發(fā)展的新一代內(nèi)核,Huawei LiteOS是面向IoT領(lǐng)域構(gòu)建的輕量級(jí)物聯(lián)網(wǎng)操作系統(tǒng)。在IoT
    發(fā)表于 08-19 10:46

    OpenHarmony支持的系統(tǒng)類(lèi)型及內(nèi)核

    本文介紹OpenHarmony所不同的系統(tǒng)類(lèi)型以及支持的內(nèi)核。系統(tǒng)類(lèi)型OpenHarmony支持以下幾種系統(tǒng)類(lèi)型:輕量系統(tǒng)(迷你系統(tǒng))給定的有限MCU類(lèi)處理器例如Arm Cortex-M
    發(fā)表于 04-19 11:29

    OpenHarmony內(nèi)核學(xué)習(xí)[1]--單獨(dú)編譯OpenHarmony標(biāo)準(zhǔn)系統(tǒng)內(nèi)核

    內(nèi)核是操作系統(tǒng)的核心,學(xué)習(xí)掌握OpenHarmony內(nèi)核對(duì)于開(kāi)發(fā)人員至關(guān)重要。筆者整理學(xué)習(xí)OpenHarmony標(biāo)準(zhǔn)系統(tǒng)內(nèi)核筆記如下:閱讀本
    發(fā)表于 02-03 10:46

    OpenHarmony瘦設(shè)備內(nèi)核移植實(shí)戰(zhàn)(一)

    一、背景 在各行各業(yè)存在很多不同的智能設(shè)備,每個(gè)設(shè)備都使用芯片去實(shí)現(xiàn)不同的業(yè)務(wù)場(chǎng)景需求。本文將以常用的STM32F407ZG芯片為例,介紹OpenHarmony瘦設(shè)備內(nèi)核移植方法,希望能對(duì)熱愛(ài)
    發(fā)表于 04-24 16:04

    Java并發(fā)編程實(shí)戰(zhàn)

    Java并發(fā)編程實(shí)戰(zhàn)
    發(fā)表于 03-19 11:24 ?7次下載

    Python數(shù)據(jù)可視化編程實(shí)戰(zhàn)

    Python數(shù)據(jù)可視化編程實(shí)戰(zhàn)資料免費(fèi)下載。
    發(fā)表于 06-01 14:37 ?29次下載

    openharmony內(nèi)核分析

    OpenHarmony內(nèi)核的源代碼分為 kernel_liteos_a 和 kernel_liteos_m 這2個(gè)代碼倉(cāng)庫(kù),其中kernel_liteos_a主要針對(duì)Cortex-A系列處理器,而kernel_liteos_m則主要針對(duì)Cortex-M系列處理器,兩者目錄
    的頭像 發(fā)表于 06-24 09:39 ?3171次閱讀

    OpenHarmony內(nèi)核是什么

    OpenHarmony源碼里面包含兩個(gè)內(nèi)核代碼,分別是liteos_A和lite_M。
    的頭像 發(fā)表于 06-24 10:08 ?3039次閱讀

    OpenHarmony技術(shù)論壇:內(nèi)核增強(qiáng)特性介紹

    OpenHarmony Tech Day·技術(shù)日》 技術(shù)論壇 內(nèi)核增強(qiáng)特性介紹 用戶(hù)能夠根據(jù)性能來(lái)自由選擇Linux和LiteOS兩種不同的內(nèi)核 Linux內(nèi)核特性:QoS智能感知調(diào)
    的頭像 發(fā)表于 04-25 15:30 ?929次閱讀
    <b class='flag-5'>OpenHarmony</b>技術(shù)論壇:<b class='flag-5'>內(nèi)核</b>增強(qiáng)特性介紹

    OpenHarmony工作委員會(huì)PMC委員萬(wàn)承臻帶你領(lǐng)略OpenHarmony3.1從內(nèi)核到框架

    OpenHarmony工作委員會(huì)PMC委員萬(wàn)承臻帶你領(lǐng)略OpenHarmony3.1從內(nèi)核到框架 OpenHarmony各版本不斷迭代不斷完善;今天以“共建新技術(shù)、開(kāi)拓新領(lǐng)域”作為
    的頭像 發(fā)表于 04-25 17:12 ?2171次閱讀
    <b class='flag-5'>OpenHarmony</b>工作委員會(huì)PMC委員萬(wàn)承臻帶你領(lǐng)略<b class='flag-5'>OpenHarmony</b>3.1從<b class='flag-5'>內(nèi)核</b>到框架

    OpenHarmony內(nèi)核任務(wù)間IPC原理

    身為深開(kāi)鴻 OS 內(nèi)核開(kāi)發(fā)師,我們常年深耕于 OpenHarmony內(nèi)核開(kāi)發(fā),希望通過(guò)分享一些工作上的經(jīng)驗(yàn),幫助大家掌握開(kāi)源知識(shí)。
    的頭像 發(fā)表于 07-12 16:45 ?1592次閱讀

    OpenHarmony瘦設(shè)備內(nèi)核移植實(shí)戰(zhàn)(一)

    背景 在各行各業(yè)存在很多不同的智能設(shè)備,每個(gè)設(shè)備都使用芯片去實(shí)現(xiàn)不同的業(yè)務(wù)場(chǎng)景需求。本文將以常用的STM32F407ZG芯片為例,介紹OpenHarmony瘦設(shè)備內(nèi)核移植方法,希望能對(duì)熱愛(ài)
    的頭像 發(fā)表于 05-11 20:16 ?907次閱讀
    <b class='flag-5'>OpenHarmony</b>瘦設(shè)備<b class='flag-5'>內(nèi)核</b>移植<b class='flag-5'>實(shí)戰(zhàn)</b>(一)

    Python編程實(shí)戰(zhàn)(源代碼)

    [源代碼]Python編程實(shí)戰(zhàn) 妙趣橫生的項(xiàng)目之旅
    發(fā)表于 06-06 17:49 ?3次下載

    OpenHarmony輕量系統(tǒng)書(shū)籍推薦《OpenHarmony輕量設(shè)備開(kāi)發(fā)理論與實(shí)戰(zhàn)

    、OpenHarmony內(nèi)核編程接口、控制I/O設(shè)備、感知環(huán)境狀態(tài)、OLED顯示屏的驅(qū)動(dòng)和控制、控制Wi-Fi、網(wǎng)絡(luò)編程以及MQTT編程。案
    的頭像 發(fā)表于 07-20 12:43 ?1020次閱讀