自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

鴻蒙內(nèi)核源碼分析(事件控制篇) | 任務(wù)間多對(duì)多的同步方案

系統(tǒng)
文章由鴻蒙社區(qū)產(chǎn)出,想要了解更多內(nèi)容請(qǐng)前往:51CTO和華為官方戰(zhàn)略合作共建的鴻蒙技術(shù)社區(qū)https://harmonyos.51cto.com

[[392639]]

想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com

官方概述

先看官方對(duì)事件的描述.

事件(Event)是一種任務(wù)間通信的機(jī)制,可用于任務(wù)間的同步。

多任務(wù)環(huán)境下,任務(wù)之間往往需要同步操作,一個(gè)等待即是一個(gè)同步。事件可以提供一對(duì)多、多對(duì)多的同步操作。

● 一對(duì)多同步模型:一個(gè)任務(wù)等待多個(gè)事件的觸發(fā)??梢允侨我庖粋€(gè)事件發(fā)生時(shí)喚醒任務(wù)處理事件,也可以是幾個(gè)事件都發(fā)生后才喚醒任務(wù)處理事件。

● 多對(duì)多同步模型:多個(gè)任務(wù)等待多個(gè)事件的觸發(fā)。

鴻蒙提供的事件具有如下特點(diǎn):

● 任務(wù)通過(guò)創(chuàng)建事件控制塊來(lái)觸發(fā)事件或等待事件。

● 事件間相互獨(dú)立,內(nèi)部實(shí)現(xiàn)為一個(gè)32位無(wú)符號(hào)整型,每一位標(biāo)識(shí)一種事件類(lèi)型。第25位不可用,因此最多可支持31種事件類(lèi)型。

● 事件僅用于任務(wù)間的同步,不提供數(shù)據(jù)傳輸功能。

● 多次向事件控制塊寫(xiě)入同一事件類(lèi)型,在被清零前等效于只寫(xiě)入一次。

● 多個(gè)任務(wù)可以對(duì)同一事件進(jìn)行讀寫(xiě)操作。

● 支持事件讀寫(xiě)超時(shí)機(jī)制。

再看事件圖

注意圖中提到了三個(gè)概念 事件控制塊 事件 任務(wù) 接下來(lái)結(jié)合代碼來(lái)理解事件模塊的實(shí)現(xiàn).

事件控制塊長(zhǎng)什么樣?

  1. typedef struct tagEvent { 
  2.     UINT32 uwEventID;        /**< Event mask in the event control block,//標(biāo)識(shí)發(fā)生的事件類(lèi)型位,事件ID,每一位標(biāo)識(shí)一種事件類(lèi)型 
  3.                                   indicating the event that has been logically processed. */ 
  4.     LOS_DL_LIST stEventList; /**< Event control block linked list *///讀取事件任務(wù)鏈表 
  5. } EVENT_CB_S, *PEVENT_CB_S; 

事件控制塊<>事件<>任務(wù) 三者關(guān)系

一定要搞明白這三者的關(guān)系,否則搞不懂事件模塊是如何運(yùn)作的.

● 任務(wù)是事件的生產(chǎn)者,通過(guò) LOS_EventWrite,向外部廣播發(fā)生了XX事件,并喚醒此前已在事件控制塊中登記過(guò)的要等待XX事件發(fā)生的XX任務(wù).

● 事件控制塊EVENT_CB_S 是記錄者,只干兩件事件:

1.uwEventID按位記錄哪些事件發(fā)生了,它只是記錄,怎么消費(fèi)它不管的.

2.stEventList記錄哪些任務(wù)在等待事件,但任務(wù)究竟在等待哪些事件它也是不記錄的

● 任務(wù)也是消費(fèi)者,通過(guò) LOS_EventRead消費(fèi),只有任務(wù)自己清楚要以什么樣的方式,消費(fèi)什么樣的事件. 先回顧下任務(wù)結(jié)構(gòu)體 LosTaskCB 對(duì)事件部分的描述如下:

  1. typedef struct { 
  2.     //...去掉不相關(guān)的部分 
  3.     VOID            *taskEvent;  //和任務(wù)發(fā)生關(guān)系的事件控制塊 
  4.     UINT32          eventMask;   //對(duì)哪些事件進(jìn)行屏蔽 
  5.     UINT32          eventMode;   //事件三種模式(LOS_WAITMODE_AND,LOS_WAITMODE_OR,LOS_WAITMODE_CLR) 
  6. } LosTaskCB;     

taskEvent 指向的就是 EVENT_CB_S

eventMask 屏蔽掉 事件控制塊 中的哪些事件

eventMode 已什么樣的方式去消費(fèi)事件,三種讀取模式

  1. #define LOS_WAITMODE_AND                    4U   
  2. #define LOS_WAITMODE_OR                     2U   
  3. #define LOS_WAITMODE_CLR                    1U   

◊ 所有事件(LOS_WAITMODE_AND):邏輯與,基于接口傳入的事件類(lèi)型掩碼eventMask,只有這些事件都已經(jīng)發(fā)生才能讀取成功,否則該任務(wù)將阻塞等待或者返回錯(cuò)誤碼。

◊ 任一事件(LOS_WAITMODE_OR):邏輯或,基于接口傳入的事件類(lèi)型掩碼eventMask,只要這些事件中有任一種事件發(fā)生就可以讀取成功,否則該任務(wù)將阻塞等待或者返回錯(cuò)誤碼。

◊ 清除事件(LOS_WAITMODE_CLR):這是一種附加讀取模式,需要與所有事件模式或任一事件模式結(jié)合使用(LOS_WAITMODE_AND | LOS_WAITMODE_CLR或 LOS_WAITMODE_OR | LOS_WAITMODE_CLR)。在這種模式下,當(dāng)設(shè)置的所有事件模式或任一事件模式讀取成功后,會(huì)自動(dòng)清除事件控制塊中對(duì)應(yīng)的事件類(lèi)型位。

● 一個(gè)事件控制塊EVENT_CB_S中的事件可以來(lái)自多個(gè)任務(wù),多個(gè)任務(wù)也可以同時(shí)消費(fèi)事件控制塊中的事件,并且這些任務(wù)之間可以沒(méi)有任何關(guān)系!

函數(shù)列表

事件可應(yīng)用于多種任務(wù)同步場(chǎng)景,在某些同步場(chǎng)景下可替代信號(hào)量。

其中讀懂 OsEventWrite 和 OsEventRead 就明白了事件模塊.

事件初始化 -> LOS_EventInit

  1. //初始化一個(gè)事件控制塊 
  2. LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB) 
  3.     UINT32 intSave; 
  4.     intSave = LOS_IntLock();//鎖中斷 
  5.     eventCB->uwEventID = 0; //其中每一位表示一種事件類(lèi)型(0表示該事件類(lèi)型未發(fā)生、1表示該事件類(lèi)型已經(jīng)發(fā)生) 
  6.     LOS_ListInit(&eventCB->stEventList);//事件鏈表初始化 
  7.     LOS_IntRestore(intSave);//恢復(fù)中斷 
  8.     return LOS_OK; 

代碼解讀:

● 事件是共享資源,所以操作期間不能產(chǎn)生中斷.

● 初始化兩個(gè)記錄者 uwEventID stEventList

事件生產(chǎn)過(guò)程 -> OsEventWrite

  1. LITE_OS_SEC_TEXT VOID OsEventWriteUnsafe(PEVENT_CB_S eventCB, UINT32 events, BOOL once, UINT8 *exitFlag) 
  2.     LosTaskCB *resumedTask = NULL
  3.     LosTaskCB *nextTask = NULL
  4.     BOOL schedFlag = FALSE
  5.  
  6.     eventCB->uwEventID |= events;//對(duì)應(yīng)位貼上標(biāo)簽 
  7.     if (!LOS_ListEmpty(&eventCB->stEventList)) {//等待事件鏈表判斷,處理等待事件的任務(wù) 
  8.         for (resumedTask = LOS_DL_LIST_ENTRY((&eventCB->stEventList)->pstNext, LosTaskCB, pendList); 
  9.              &resumedTask->pendList != &eventCB->stEventList;) {//循環(huán)獲取任務(wù)鏈表 
  10.             nextTask = LOS_DL_LIST_ENTRY(resumedTask->pendList.pstNext, LosTaskCB, pendList);//獲取任務(wù)實(shí)體 
  11.             if (OsEventResume(resumedTask, eventCB, events)) {//是否恢復(fù)任務(wù) 
  12.                 schedFlag = TRUE;//任務(wù)已加至就緒隊(duì)列,申請(qǐng)發(fā)生一次調(diào)度 
  13.             } 
  14.             if (once == TRUE) {//是否只處理一次任務(wù) 
  15.                 break;//退出循環(huán) 
  16.             } 
  17.             resumedTask = nextTask;//檢查鏈表中下一個(gè)任務(wù) 
  18.         } 
  19.     } 
  20.  
  21.     if ((exitFlag != NULL) && (schedFlag == TRUE)) {//是否讓外面調(diào)度 
  22.         *exitFlag = 1; 
  23.     } 
  24. //寫(xiě)入事件 
  25. LITE_OS_SEC_TEXT STATIC UINT32 OsEventWrite(PEVENT_CB_S eventCB, UINT32 events, BOOL once) 
  26.     UINT32 intSave; 
  27.     UINT8 exitFlag = 0; 
  28.  
  29.     SCHEDULER_LOCK(intSave);    //禁止調(diào)度 
  30.     OsEventWriteUnsafe(eventCB, events, once, &exitFlag);//寫(xiě)入事件 
  31.     SCHEDULER_UNLOCK(intSave);  //允許調(diào)度 
  32.  
  33.     if (exitFlag == 1) { //需要發(fā)生調(diào)度 
  34.         LOS_MpSchedule(OS_MP_CPU_ALL);//通知所有CPU調(diào)度 
  35.         LOS_Schedule();//執(zhí)行調(diào)度 
  36.     } 
  37.     return LOS_OK; 

代碼解讀:

1.給對(duì)應(yīng)位貼上事件標(biāo)簽,eventCB->uwEventID |= events; 注意uwEventID是按位管理的.每個(gè)位代表一個(gè)事件是否寫(xiě)入,例如 uwEventID = 00010010 代表產(chǎn)生了 1,4 事件

2.循環(huán)從stEventList鏈表中取出等待這個(gè)事件的任務(wù)判斷是否喚醒任務(wù). OsEventResume

  1. //事件恢復(fù),判斷是否喚醒任務(wù) 
  2. LITE_OS_SEC_TEXT STATIC UINT8 OsEventResume(LosTaskCB *resumedTask, const PEVENT_CB_S eventCB, UINT32 events) 
  3.     UINT8 exitFlag = 0;//是否喚醒 
  4.  
  5.     if (((resumedTask->eventMode & LOS_WAITMODE_OR) && ((resumedTask->eventMask & events) != 0)) || 
  6.         ((resumedTask->eventMode & LOS_WAITMODE_AND) && 
  7.         ((resumedTask->eventMask & eventCB->uwEventID) == resumedTask->eventMask))) {//邏輯與 和 邏輯或 的處理 
  8.         exitFlag = 1;  
  9.  
  10.         resumedTask->taskEvent = NULL
  11.         OsTaskWake(resumedTask);//喚醒任務(wù),加入就緒隊(duì)列 
  12.     } 
  13.  
  14.     return exitFlag; 

3.喚醒任務(wù)OsTaskWake只是將任務(wù)重新加入就緒隊(duì)列,需要立即申請(qǐng)一次調(diào)度 LOS_Schedule .

事件消費(fèi)過(guò)程 -> OsEventRead

  1. LITE_OS_SEC_TEXT STATIC UINT32 OsEventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout, 
  2.                                            BOOL once) 
  3.     UINT32 ret; 
  4.     UINT32 intSave; 
  5.     SCHEDULER_LOCK(intSave); 
  6.     ret = OsEventReadImp(eventCB, eventMask, mode, timeout, once);//讀事件實(shí)現(xiàn)函數(shù) 
  7.     SCHEDULER_UNLOCK(intSave); 
  8.     return ret; 
  9.  
  10. //讀取指定事件類(lèi)型的實(shí)現(xiàn)函數(shù),超時(shí)時(shí)間為相對(duì)時(shí)間:?jiǎn)挝粸門(mén)ick 
  11. LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadImp(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, 
  12.                                               UINT32 timeout, BOOL once) 
  13.     UINT32 ret = 0; 
  14.     LosTaskCB *runTask = OsCurrTaskGet(); 
  15.     runTask->eventMask = eventMask; 
  16.     runTask->eventMode = mode; 
  17.     runTask->taskEvent = eventCB;//事件控制塊 
  18.     ret = OsTaskWait(&eventCB->stEventList, timeout, TRUE);//任務(wù)進(jìn)入等待狀態(tài),掛入阻塞鏈表 
  19.     if (ret == LOS_ERRNO_TSK_TIMEOUT) {//如果返回超時(shí) 
  20.         runTask->taskEvent = NULL
  21.         return LOS_ERRNO_EVENT_READ_TIMEOUT; 
  22.     } 
  23.     ret = OsEventPoll(&eventCB->uwEventID, eventMask, mode);//檢測(cè)事件是否符合預(yù)期 
  24.     return ret; 

代碼解讀:

● 事件控制塊是給任務(wù)使用的, 任務(wù)給出讀取一個(gè)事件的條件eventMask 告訴系統(tǒng)屏蔽掉這些事件,對(duì)屏蔽的事件不感冒.

1. eventMask 告訴系統(tǒng)屏蔽掉這些事件,對(duì)屏蔽的事件不感冒.

2. eventMode 已什么樣的方式去消費(fèi)事件,是必須都滿(mǎn)足給的條件,還是只滿(mǎn)足一個(gè)就響應(yīng).

3. 條件給完后,自己進(jìn)入等待狀態(tài) OsTaskWait,等待多久 timeout決定,任務(wù)自己說(shuō)了算.

4. OsEventPoll檢測(cè)事件是否符合預(yù)期,啥意思?看下它的代碼就知道了.

  1. //根據(jù)用戶(hù)傳入的事件值、事件掩碼及校驗(yàn)?zāi)J?,返回用?hù)傳入的事件是否符合預(yù)期 
  2. LITE_OS_SEC_TEXT UINT32 OsEventPoll(UINT32 *eventID, UINT32 eventMask, UINT32 mode) 
  3.     UINT32 ret = 0;//事件是否發(fā)生了 
  4.  
  5.     LOS_ASSERT(OsIntLocked());//斷言不允許中斷了 
  6.     LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));//任務(wù)自旋鎖 
  7.  
  8.     if (mode & LOS_WAITMODE_OR) {//如果模式是讀取掩碼中任意事件 
  9.         if ((*eventID & eventMask) != 0) { 
  10.             ret = *eventID & eventMask; //發(fā)生了 
  11.         } 
  12.     } else {//等待全部事件發(fā)生 
  13.         if ((eventMask != 0) && (eventMask == (*eventID & eventMask))) {//必須滿(mǎn)足全部事件發(fā)生 
  14.             ret = *eventID & eventMask; //發(fā)生了 
  15.         } 
  16.     } 
  17.  
  18.     if (ret && (mode & LOS_WAITMODE_CLR)) {//是否清除事件 
  19.         *eventID = *eventID & ~ret;  
  20.     } 
  21.  
  22.     return ret;  

編程實(shí)例

本實(shí)例實(shí)現(xiàn)如下流程。

示例中,任務(wù)Example_TaskEntry創(chuàng)建一個(gè)任務(wù)Example_Event,Example_Event讀事件阻塞,Example_TaskEntry向該任務(wù)寫(xiě)事件??梢酝ㄟ^(guò)示例日志中打印的先后順序理解事件操作時(shí)伴隨的任務(wù)切換。

● 在任務(wù)Example_TaskEntry創(chuàng)建任務(wù)Example_Event,其中任務(wù)Example_Event優(yōu)先級(jí)高于Example_TaskEntry。

● 在任務(wù)Example_Event中讀事件0x00000001,阻塞,發(fā)生任務(wù)切換,執(zhí)行任務(wù)Example_TaskEntry。

● 在任務(wù)Example_TaskEntry向任務(wù)Example_Event寫(xiě)事件0x00000001,發(fā)生任務(wù)切換,執(zhí)行任務(wù)Example_Event。

● Example_Event得以執(zhí)行,直到任務(wù)結(jié)束。

● Example_TaskEntry得以執(zhí)行,直到任務(wù)結(jié)束。

  1. #include "los_event.h" 
  2. #include "los_task.h" 
  3. #include "securec.h" 
  4.  
  5. /* 任務(wù)ID */ 
  6. UINT32 g_testTaskId; 
  7.  
  8. /* 事件控制結(jié)構(gòu)體 */ 
  9. EVENT_CB_S g_exampleEvent; 
  10.  
  11. /* 等待的事件類(lèi)型 */ 
  12. #define EVENT_WAIT 0x00000001 
  13.  
  14. /* 用例任務(wù)入口函數(shù) */ 
  15. VOID Example_Event(VOID) 
  16.     UINT32 ret; 
  17.     UINT32 event; 
  18.  
  19.     /* 超時(shí)等待方式讀事件,超時(shí)時(shí)間為100 ticks, 若100 ticks后未讀取到指定事件,讀事件超時(shí),任務(wù)直接喚醒 */ 
  20.     printf("Example_Event wait event 0x%x \n", EVENT_WAIT); 
  21.  
  22.     event = LOS_EventRead(&g_exampleEvent, EVENT_WAIT, LOS_WAITMODE_AND, 100); 
  23.     if (event == EVENT_WAIT) { 
  24.         printf("Example_Event,read event :0x%x\n", event); 
  25.     } else { 
  26.         printf("Example_Event,read event timeout\n"); 
  27.     } 
  28.  
  29. UINT32 Example_TaskEntry(VOID) 
  30.     UINT32 ret; 
  31.     TSK_INIT_PARAM_S task1; 
  32.  
  33.     /* 事件初始化 */ 
  34.     ret = LOS_EventInit(&g_exampleEvent); 
  35.     if (ret != LOS_OK) { 
  36.         printf("init event failed .\n"); 
  37.         return -1; 
  38.     } 
  39.  
  40.     /* 創(chuàng)建任務(wù) */ 
  41.     (VOID)memset_s(&task1, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); 
  42.     task1.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Event; 
  43.     task1.pcName       = "EventTsk1"
  44.     task1.uwStackSize  = OS_TSK_DEFAULT_STACK_SIZE; 
  45.     task1.usTaskPrio   = 5; 
  46.     ret = LOS_TaskCreate(&g_testTaskId, &task1); 
  47.     if (ret != LOS_OK) { 
  48.         printf("task create failed .\n"); 
  49.         return LOS_NOK; 
  50.     } 
  51.  
  52.     /* 寫(xiě)g_testTaskId 等待事件 */ 
  53.     printf("Example_TaskEntry write event .\n"); 
  54.  
  55.     ret = LOS_EventWrite(&g_exampleEvent, EVENT_WAIT); 
  56.     if (ret != LOS_OK) { 
  57.         printf("event write failed .\n"); 
  58.         return LOS_NOK; 
  59.     } 
  60.  
  61.     /* 清標(biāo)志位 */ 
  62.     printf("EventMask:%d\n", g_exampleEvent.uwEventID); 
  63.     LOS_EventClear(&g_exampleEvent, ~g_exampleEvent.uwEventID); 
  64.     printf("EventMask:%d\n", g_exampleEvent.uwEventID); 
  65.  
  66.     /* 刪除任務(wù) */ 
  67.     ret = LOS_TaskDelete(g_testTaskId); 
  68.     if (ret != LOS_OK) { 
  69.         printf("task delete failed .\n"); 
  70.         return LOS_NOK; 
  71.     } 
  72.  
  73.     return LOS_OK; 

運(yùn)行結(jié)果

  1. Example_Event wait event 0x1  
  2. Example_TaskEntry write event . 
  3. Example_Event,read event :0x1 
  4. EventMask:1 
  5. EventMask:0 

參與貢獻(xiàn)

● 訪(fǎng)問(wèn)注解倉(cāng)庫(kù)地址

Fork 本倉(cāng)庫(kù) >> 新建 Feat_xxx 分支 >> 提交代碼注解 >> 新建 Pull Request

● 新建 Issue

想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com

 

責(zé)任編輯:jianghua 來(lái)源: 鴻蒙社區(qū)
相關(guān)推薦

2021-04-13 09:20:15

鴻蒙HarmonyOS應(yīng)用開(kāi)發(fā)

2021-03-11 11:14:39

鴻蒙HarmonyOS應(yīng)用

2021-04-09 16:39:41

鴻蒙HarmonyOS應(yīng)用

2021-04-08 09:32:17

鴻蒙HarmonyOS應(yīng)用

2021-04-07 15:11:26

鴻蒙HarmonyOS應(yīng)用

2010-08-24 09:47:05

LINQ to SQL

2022-04-13 11:02:12

鴻蒙事件模塊事件Event

2009-06-04 16:14:22

Hibernate一對(duì)Hibernate一對(duì)Hibernate多對(duì)

2009-07-21 17:39:50

iBATIS的多對(duì)多映

2021-06-04 09:57:49

鴻蒙HarmonyOS應(yīng)用

2021-05-13 09:47:08

鴻蒙HarmonyOS應(yīng)用

2021-01-22 09:47:22

鴻蒙HarmonyOS應(yīng)用開(kāi)發(fā)

2021-03-15 15:18:16

鴻蒙HarmonyOS應(yīng)用

2020-10-10 08:57:30

網(wǎng)絡(luò)攻擊微盟刪庫(kù)事件網(wǎng)絡(luò)安全

2021-05-20 09:50:20

鴻蒙HarmonyOS應(yīng)用

2020-10-23 10:10:59

Promise前端代碼

2018-08-20 16:00:23

MySQL并發(fā)控制MVCC

2010-04-15 09:09:02

Hibernate

2021-05-14 10:34:29

鴻蒙HarmonyOS應(yīng)用

2021-03-30 15:30:44

鴻蒙HarmonyOS應(yīng)用開(kāi)發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)