OpenHarmony智能開發(fā)套件—內(nèi)核編程(下)
想了解更多關(guān)于開源的內(nèi)容,請(qǐng)?jiān)L問:
前言
本篇基于上一篇OpenHarmony智能開發(fā)套件[內(nèi)核編程·上]繼續(xù)介紹OpenHarmony在智能開發(fā)套件Hi3861上的內(nèi)核編程學(xué)習(xí)。
內(nèi)核編程
還不了解OpenHarmony內(nèi)核的伙伴們可以參考上篇文章,上篇已經(jīng)簡單通俗地介紹了OpenHarmony的內(nèi)核。
OpenHarmony智能開發(fā)套件內(nèi)核編程·上
互斥鎖
線程的狀態(tài)
在介紹互斥鎖之前,我們有必要去了解一下線程的狀態(tài),或者說線程的生命周期。避免伙伴們因?yàn)椴粔蚴煜ぞ€程而對(duì)這個(gè)互斥鎖的概念感到困難。
首先介紹一下線程的幾個(gè)狀態(tài),他們分別有:
- 創(chuàng)建
創(chuàng)建線程,在OpenHarmony的源碼中,線程的屬性被封裝成了一個(gè)名為”osThreadAttr_t“的結(jié)構(gòu)體
typedef struct {
const char *name;
uint32_t attr_bits;
void *cb_mem;
uint32_t cb_size;
void *stack_mem;
uint32_t stack_size;
osPriority_t priority;
TZ_ModuleId_t tz_module;
uint32_t reserved;
} osThreadAttr_t;
- name:線程的名稱。
- 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)行起來。
- 運(yùn)行
在上篇我們介紹了一個(gè)關(guān)于線程的API,他可以將就緒狀態(tài)的線程加入到活躍線程組
osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr);
此時(shí)的線程將會(huì)占用部分cpu資源執(zhí)行他的程序,直到程序結(jié)束,或者線程被阻塞,cpu被搶占等。
- 阻塞
線程阻塞,可以理解為線程無法繼續(xù)往下執(zhí)行,但時(shí)線程執(zhí)行的程序不會(huì)直接退出,他會(huì)進(jìn)入到等待的狀態(tài),直到相關(guān)資源被釋放,線程可以繼續(xù)執(zhí)行。
- 終止
上篇我們介紹了線程終止的API
sStatus_t status = osThreadTerminate(osThreadId_t tid);
此時(shí)線程完成了自己的代碼邏輯,我們方可主動(dòng)調(diào)用該API徹底刪除這個(gè)線程。
當(dāng)然如果具體細(xì)分,其實(shí)不止這五個(gè)狀態(tài),但是了解了這五個(gè)狀態(tài)就足夠了。下面我們來聊聊什么是互斥鎖。
互斥鎖簡介
互斥鎖的應(yīng)用場景時(shí)處理多線程,資源訪問的問題。這里還是給大家舉一個(gè)例子:動(dòng)物園賣票。
在我們的程序設(shè)計(jì)中,往往會(huì)有共有資源,每個(gè)線程都可以進(jìn)來訪問這些資源。這里的共有資源就是我們的門票,一個(gè)售票口就是一個(gè)線程,當(dāng)有人來窗口買票,我們的門票就會(huì)減少一張。當(dāng)然一個(gè)動(dòng)物園的流量時(shí)巨大的,我們不能只設(shè)立一個(gè)售票口,這樣的效率是很低的。京東淘寶搶購秒殺也一樣,我們必須設(shè)立多個(gè)窗口,在同一時(shí)刻為多個(gè)人處理業(yè)務(wù)。多線程解決了效率問題但也帶來了安全隱患。
我們假設(shè)一個(gè)這樣的場景,動(dòng)物園僅剩一張門票,但是有兩個(gè)在不同的窗口同時(shí)付了錢,當(dāng)售票員為他們拿票的時(shí)候就會(huì)發(fā)現(xiàn),少了一張票,兩個(gè)人都付了錢都想要那張票,就陷入了一個(gè)死局,無奈動(dòng)物園只能讓他們都進(jìn)去。但是在程序中體現(xiàn)的可能就是一個(gè)bug,動(dòng)物園的門票剩余數(shù)為:-1。
if(count > 0){
count--;
}
售票的邏輯很簡單,只要票數(shù)大于零,還有票能賣,那就在此基礎(chǔ)上減掉一。問題就在于,兩個(gè)線程同時(shí)在count = 1的時(shí)候通過了if判斷,都執(zhí)行的count–;那么就會(huì)出現(xiàn)了count = -1,也就是票數(shù)為負(fù) 的bug結(jié)果。
互斥鎖的出現(xiàn)就很好地解決了一個(gè)問題,他能夠阻止上面兩個(gè)線程同時(shí)訪問資源的同步行為,也就是說當(dāng)一個(gè)線程進(jìn)入這個(gè)if語句后,別的線程都不能進(jìn)入。形象起來說,就像對(duì)這段代碼加了鎖,只有有鑰匙的線程才能夠訪問它。
互斥鎖API
通過對(duì)幾個(gè)API的介紹,讓大家知道怎么為一段代碼加上互斥鎖
- 創(chuàng)建互斥鎖。
與線程的定義一樣,互斥鎖也封裝成了一個(gè)結(jié)構(gòu)體
typedef struct {
/** Mutex name */
const char *name;
/** Reserved attribute bits */
uint32_t attr_bits;
/** Memory for the mutex control block */
void *cb_mem;
/** Size of the memory for the mutex control block */
uint32_t cb_size;
} osMutexAttr_t;
- name:互斥鎖的名稱
- attr_bits:保留的屬性位
- cb_mem:互斥鎖控制塊的內(nèi)存
- cb_size:互斥鎖控制塊內(nèi)存的大小
- 獲取互斥鎖的id。
osMutexId_t osMutexNew(const osMutexAttr_t *attr);
將我們上面定義的互斥鎖屬性傳入函數(shù),返回互斥鎖的id
- 線程獲取互斥鎖
osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout);
傳入互斥鎖id,設(shè)置我們的延遲時(shí)間,當(dāng)線程獲取到我們的互斥鎖時(shí),返回的狀態(tài)是osOK。
下面是全部的狀態(tài)碼。
typedef enum {
/** Operation completed successfully */
osOK = 0,
/** Unspecified error */
osError = -1,
/** Timeout */
osErrorTimeout = -2,
/** Resource error */
osErrorResource = -3,
/** Incorrect parameter */
osErrorParameter = -4,
/** Insufficient memory */
osErrorNoMemory = -5,
/** Service interruption */
osErrorISR = -6,
/** Reserved. It is used to prevent the compiler from optimizing enumerations. */
osStatusReserved = 0x7FFFFFFF
} osStatus_t;
- 釋放鎖。
osStatus_t osMutexRelease(osMutexId_t mutex_id);
當(dāng)我們的線程執(zhí)行完業(yè)務(wù)后需要把鎖釋放出來,讓別的線程獲取鎖,執(zhí)行業(yè)務(wù)。當(dāng)然這個(gè)過程是線程之間的競爭,一個(gè)線程可能一直得不到鎖,一個(gè)線程也可能剛釋放鎖又獲得鎖,我們可以添加休眠操作,提高鎖在各個(gè)線程間的分配。
其他API請(qǐng)參考:
操作
- 新建樣例目錄。
applications/sample/wifi-iot/app/mutex_demo - 新建源文件和gn文件。
applications/sample/wifi-iot/app/mutex_demo/mutex.c
applications/sample/wifi-iot/app/mutex_demo/BUILD.gn
- 源碼編寫。
因?yàn)橐呀?jīng)介紹了主要的API,這里就直接給伙伴們上源碼了。
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
// 模擬動(dòng)物園門票數(shù)
static int count = 100;
// 售票業(yè)務(wù)線程
void outThread(void *args){
// 獲取互斥鎖
osMutexId_t *mid = (osMutexId_t *)args;
// 每個(gè)線程都在不停地買票
while(1){
// 獲取鎖,進(jìn)入業(yè)務(wù)流程
if(osMutexAcquire(*mid, 100) == osOK){
if(count > 0){
count--;
// 設(shè)置提示信息
printf("[Mutex Test] Thread %s get a value, the less is %d.\r\n", osThreadGetName(osThreadGetId()), count);
} else {
// 告知這些線程已經(jīng)沒有門票賣了,線程結(jié)束
printf("[Mutex Test] The value is out!\r\n");
osThreadTerminate(osThreadGetId());
}
}
// 釋放鎖
osMutexRelease(*mid);
osDelay(5);
}
}
// 創(chuàng)建線程封裝
osThreadId_t createThreads(char *name, osThreadFunc_t func, void *args){
osThreadAttr_t attr = {
name, 0, NULL, 0, NULL, 1024, osPriorityNormal, 0, 0
};
osThreadId_t tid = osThreadNew(func, args, &attr);
return tid;
}
// 主函數(shù)實(shí)現(xiàn)多線程的創(chuàng)建,執(zhí)行買票業(yè)務(wù)
void mutexMain(void){
// 創(chuàng)建互斥鎖
osMutexAttr_t attr = {0};
// 獲取互斥鎖的id
osMutexId_t mid = osMutexNew(&attr);
if(mid == NULL){
printf("[Mutex Test] Failed to create a mutex!\r\n");
}
// 創(chuàng)建多線程
osThreadId_t tid1 = createThreads("Thread_1", (osThreadFunc_t)outThread, &mid);
osThreadId_t tid2 = createThreads("Thread_2", (osThreadFunc_t)outThread, &mid);
osThreadId_t tid3 = createThreads("Thread_3", (osThreadFunc_t)outThread, &mid);
osDelay(1000);
}
// 測試線程
void MainTest(void){
osThreadId_t tid = createThreads("MainTest", (osThreadFunc_t)mutexMain, NULL);
}
APP_FEATURE_INIT(MainTest);
- 編寫gn文件。
static_library("mutex_demo"){
sources = [
"mutex.c"
]
include_dirs = [
"http://commonlibrary/utils_lite/include",
"http://device/soc/hisilicon/hi3861v100/hi3861_adapter/kal/cmsis"
]
}
- 編寫app目錄下的gn文件。
結(jié)果展示
可能有的伙伴們看到這里不太清晰,會(huì)覺得這段代碼真的上鎖了嗎?
if(osMutexAcquire(*mid, 100) == osOK){
if(count > 0){
count--;
printf("[Mutex Test] Thread %s get a value, the less is %d.\r\n", osThreadGetName(osThreadGetId()), count);
} else {
printf("[Mutex Test] The value is out!\r\n");
osThreadTerminate(osThreadGetId());
}
}
那么我們可以不使用互斥鎖再次執(zhí)行這段代碼。
結(jié)果展示如下:
注:這里筆者還另外多加了3個(gè)線程,一共六個(gè)線程,可以看出來控制臺(tái)的輸出很混亂,當(dāng)一個(gè)線程在執(zhí)行輸出指令時(shí),另一個(gè)線程也插了進(jìn)來執(zhí)行輸出指令所造成的,再看票數(shù),也是出現(xiàn)了明顯的問題。因此互斥鎖在處理多線程問題時(shí),起到了非常重要的作用。
可能有伙伴好奇,怎么沒有負(fù)數(shù)票的出現(xiàn),筆者作為學(xué)習(xí)者,代碼能力也有限,可能寫出來的案例并不是非常精確,僅供參考。
信號(hào)量
對(duì)大部分初學(xué)者而言,這又是一個(gè)新名詞,什么是信號(hào)量?其實(shí)他跟我們上篇介紹的互斥鎖很像。互斥鎖是在多線程中允許一個(gè)線程訪問資源,信號(hào)量是在多線程中允許多個(gè)線程訪問資源。
初學(xué)者一定會(huì)感到困惑,為了解決多線程訪問資源的風(fēng)險(xiǎn)我們限制只能有一個(gè)線程在某一時(shí)刻訪問資源,現(xiàn)在這個(gè)信號(hào)量怎么有允許多個(gè)線程訪問資源呢。筆者剛開始也比較困惑,結(jié)合一些案例理解后,也是明白了這樣的設(shè)計(jì)初衷。實(shí)際上,信號(hào)量,互斥鎖本就是兩種不同的多形成同步運(yùn)行機(jī)制,在特定的應(yīng)用場景下,有特定的需求,而信號(hào)量,互斥鎖可以滿足不同的需求,具體是什么需求呢,舉個(gè)例子給大家。
賣票,我們的確需要互斥鎖解決多線程可能帶來的錯(cuò)誤,那么如果是驗(yàn)票呢,為了提高效率,我們開設(shè)多個(gè)入口同時(shí)驗(yàn)票且不會(huì)發(fā)生沖突,信號(hào)量就做到了限制線程數(shù)量訪問資源的作用。如果我們不限制并發(fā)的數(shù)量,我們的程序占用資源可能會(huì)非常大,甚至崩潰,就像檢票的入口沒有被明確入口數(shù)量一樣,門口的人們會(huì)亂成一片。
信號(hào)量API
- 創(chuàng)建信號(hào)量。
osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr);
參數(shù)解釋:最大容量量,初始容納量,信號(hào)量屬性。
最大容納量說明了,我們的資源最大能被多少線程訪問。
初始容納量說明了,我們當(dāng)前實(shí)際能有多少線程訪問資源,因?yàn)橐粋€(gè)信號(hào)對(duì)應(yīng)一個(gè)線程的許可。
返回值:信號(hào)量的id。
- 獲取信號(hào)量。
osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout);
參數(shù)解釋:信號(hào)量的id,等待時(shí)長。
返回值:狀態(tài)碼 (介紹很多遍了,就不說明了)。
我們往往會(huì)在timoeout處設(shè)置為 oswaitForever。
#define osWaitForever 0xFFFFFFFFU
這樣我們的線程就會(huì)一直等,直到有信號(hào)量空出來被他獲取,才執(zhí)行后續(xù)的代碼。
- 釋放信號(hào)量。
osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id);
很簡單,傳入信號(hào)量的id,就可以釋放一個(gè)信號(hào)量出來。
其他的API請(qǐng)參考:
任務(wù)
有4個(gè)售票窗,2個(gè)檢票口,每次會(huì)有4個(gè)人來買票,然后去檢票,用互斥鎖控制購票,信號(hào)量控制檢票。
操作
- 新建樣例目錄。
applications/sample/wifi-iot/app/semaphore_demo。 - 新建源文件和gn文件。
applications/sample/wifi-iot/app/semaphore_demo/semaphore.c。
applications/sample/wifi-iot/app/semaphore_demo/BUILD.gn。
- 源碼編寫。
直接上源碼了。
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
// 售票口 4
#define OUT_NUM 4
// 檢票口 2
#define IN_NUM 2
// 信號(hào)量
osSemaphoreId_t sid;
// 待檢票人數(shù)
static int people = 0;
// 售票業(yè)務(wù)
void outThread(void *args){
// 獲取互斥鎖
osMutexId_t *mid = (osMutexId_t *)args;
while(1){
if(osMutexAcquire(*mid, 100) == osOK){
// 賣一張票,帶檢票的人數(shù)就會(huì)加一位
people++;
printf("[SEMAPHORE TEST] out, people: %d.\r\n", people);
}
osMutexRelease(*mid);
osDelay(50);
}
}
// 檢票業(yè)務(wù)
void inThread(void *args){
// 獲取信號(hào)量
osSemaphoreAcquire(sid, osWaitForever);
while(1){
if(people > 0){
people--;
printf("[SEMAPHORE TEST] in, people: %d.\r\n", people);
}
osSemaphoreRelease(sid);
osDelay(100);
}
}
// 創(chuàng)建線程封裝
osThreadId_t createThreads(char *name, osThreadFunc_t func, void *args){
osThreadAttr_t attr = {
name, 0, NULL, 0, NULL, 1024 * 2, osPriorityNormal, 0, 0
};
osThreadId_t tid = osThreadNew(func, args, &attr);
return tid;
}
// 主線程
void SemaphoreMain(void){
// 創(chuàng)建信號(hào)量
sid = osSemaphoreNew(IN_NUM, IN_NUM, NULL);
// 創(chuàng)建互斥鎖
osMutexAttr_t attr = {0};
// 獲取互斥鎖的id
osMutexId_t mid = osMutexNew(&attr);
// 創(chuàng)建售票線程
for(int i = 0; i < OUT_NUM; i++){
createThreads("", (osThreadFunc_t)outThread, &mid);
}
// 創(chuàng)建檢票線程
for(int i = 0; i < IN_NUM; i++){
createThreads("", (osThreadFunc_t)inThread, NULL);
}
}
// 測試函數(shù)
void MainTest(){
createThreads("MainTest", (osThreadFunc_t)SemaphoreMain, NULL);
}
APP_FEATURE_INIT(MainTest);
- 編寫gn文件。
static_library("semaphore_demo"){
sources = [
"semaphore.c"
]
include_dirs = [
"http://utils/native/lite/include",
]
}
- 編寫app目錄下的gn文件。
結(jié)果展示
大家可以加長檢票業(yè)務(wù)的休眠時(shí)間,我們的檢票口是兩個(gè),in的業(yè)務(wù)一定是兩個(gè)一起執(zhí)行的。
總之信號(hào)量和互斥鎖是多線程管理中的重點(diǎn),大家一定要好好體會(huì)他們的作用和區(qū)別。
消息隊(duì)列
本篇的最后我們來介紹消息隊(duì)列。隊(duì)列相信大部分朋友都不陌生,是一種基本且常用的數(shù)據(jù)結(jié)構(gòu),這里筆者就不介紹隊(duì)列的相關(guān)信息了。那么什么是消息隊(duì)列呢?有什么應(yīng)用場景呢。
消息隊(duì)列也是多線程,高并發(fā)中的處理方式,大家可以理解為“同步入隊(duì),異步出隊(duì)”。老樣子從一個(gè)案例解釋,網(wǎng)購秒殺。
在網(wǎng)購秒殺時(shí),會(huì)有上萬甚至上百萬的流量涌入服務(wù)器,下單即可看作一個(gè)請(qǐng)求,向服務(wù)器請(qǐng)求獲取某個(gè)商品。服務(wù)器處理,生成買家的訂單號(hào)。當(dāng)然強(qiáng)大服務(wù)器的也無法在同一時(shí)刻支持如此多的請(qǐng)求,并且商品的數(shù)量也不足被所有人購買,這個(gè)時(shí)候,我們的消息隊(duì)列就會(huì)同步接受大家的請(qǐng)求,所有的請(qǐng)求都會(huì)被壓進(jìn)一個(gè)隊(duì)列中,服務(wù)器從隊(duì)列中依次獲取消息,確保不會(huì)因?yàn)橘Y源被占用而導(dǎo)致系統(tǒng)崩潰。
#### 消息隊(duì)列API
- 創(chuàng)建消息隊(duì)列。
osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr);
參數(shù)說明:
- msg_count:消息隊(duì)列中的消息數(shù)量。
- msg_size:消息隊(duì)列中每個(gè)消息的大小,通常我們的消息會(huì)用一個(gè)結(jié)構(gòu)體來自定義消息的內(nèi)容
- attr:指向消息隊(duì)列屬性。
該函數(shù)的返回值是osMessageQueueId_t類型,表示消息隊(duì)列的ID。如果創(chuàng)建消息隊(duì)列失敗,函數(shù)將返回NULL。
- 向消息隊(duì)列加入消息。
osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout);
參數(shù)說明:
- mq_id:消息隊(duì)列的ID,通過調(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類型,表示函數(shù)執(zhí)行的結(jié)果。
- 從消息隊(duì)列中接受消息。
osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout);
參數(shù)說明:
- mq_id:消息隊(duì)列的ID,通過調(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類型,表示函數(shù)執(zhí)行的結(jié)果。
- 刪除消息隊(duì)列。
osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id);
參數(shù)說明:
- mq_id:消息隊(duì)列的ID,通過調(diào)用osMessageQueueNew函數(shù)獲得。
該函數(shù)的返回值是osStatus_t類型,表示函數(shù)執(zhí)行的結(jié)果。
其他的API請(qǐng)參考:
任務(wù)
模擬搶購秒殺,假設(shè)我們有10個(gè)線程,15個(gè)大小的消息隊(duì)列,5件商品。
操作
- 新建樣例目錄。
applications/sample/wifi-iot/app/queue_demo。 - 新建源文件和gn文件。
applications/sample/wifi-iot/app/queue_demo/queue.c。
applications/sample/wifi-iot/app/queue_demo/BUILD.gn。
- 編寫源碼。
直接上源碼。
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
// 定義消息隊(duì)列的大小
#define QUEUE_SIZE 15
// 定義請(qǐng)求數(shù)量
#define REQ_SIZE 10
// 定義消息的結(jié)構(gòu)
typedef struct{
osThreadId_t tid;
} message_queue;
// 創(chuàng)建消息隊(duì)列id
osMessageQueueId_t qid;
// 模擬發(fā)送業(yè)務(wù)
void sendThread(void){
// 定義一個(gè)消息結(jié)構(gòu)
message_queue sentry;
sentry.tid = osThreadGetId();
osDelay(100);
// 消息入隊(duì)
osMessageQueuePut(qid, (const void*)&sentry, 0, osWaitForever);
// 設(shè)置提示信息
printf("[MESSAGEQUEUE TEST] %d send a message.\r\n", sentry.tid);
}
// 模擬處理業(yè)務(wù)
void receiverThread(void){
// 定義一個(gè)消息結(jié)構(gòu)
message_queue rentry;
int less = 5;
while(less > 0){
osMessageQueueGet(qid, (void *)&rentry, NULL, osWaitForever);
less--;
printf("[MESSAGEQUEUE TEST] %d get a product, less = %d.\r\n", rentry.tid, less);
osDelay(5);
}
printf("[MESSAGEQUEUE TEST] over!\r\n");
}
// 創(chuàng)建線程封裝
osThreadId_t createThreads(char *name, osThreadFunc_t func, void *args){
osThreadAttr_t attr = {
name, 0, NULL, 0, NULL, 1024 * 2, osPriorityNormal, 0, 0
};
osThreadId_t tid = osThreadNew(func, args, &attr);
return tid;
}
// 主線程
void MessageQueueMain(void){
// 創(chuàng)建一個(gè)消息隊(duì)列
qid = osMessageQueueNew(QUEUE_SIZE, sizeof(message_queue), NULL);
// 創(chuàng)建發(fā)送線程
for(int i = 0; i < REQ_SIZE; i++){
createThreads("", (osThreadFunc_t)sendThread, NULL);
}
osDelay(5);
// 創(chuàng)建接收線程
createThreads("", (osThreadFunc_t)receiverThread, NULL);
osDelay(500);
// 刪除消息隊(duì)列
osMessageQueueDelete(qid);
}
// 測試函數(shù)
void MainTest(){
createThreads("MainTest", (osThreadFunc_t)MessageQueueMain, NULL);
}
APP_FEATURE_INIT(MainTest);
- 編寫gn。
static_library("queue_demo"){
sources = [
"queue.c",
]
include_dirs = [
"http://utils/native/lite/include",
]
}
- 編寫app目錄下的gn。
結(jié)果展示
因?yàn)榫€程創(chuàng)建是循環(huán)創(chuàng)建的,先創(chuàng)建的線程就優(yōu)先發(fā)送了請(qǐng)求,可以看的出來,前五個(gè)線程搶到了商品。如果線程可以同時(shí)發(fā)送請(qǐng)求,爭搶入隊(duì)的時(shí)機(jī),模擬將會(huì)更加準(zhǔn)確一些,這里只是簡單的模擬。
結(jié)束語
至此內(nèi)核的基礎(chǔ)內(nèi)容就給伙伴們介紹完了,內(nèi)核作為一個(gè)系統(tǒng)的底層起到了相當(dāng)重要的作用,大家要好好體會(huì),希望能幫助到學(xué)習(xí)OpenHarmony的伙伴們。