1.概述
在《RTA-OS系列介紹-Task》部分我們介紹了任務分為基礎任務與擴展任務,兩者的主要區別為,擴展任務多了waiting狀態,那Waiting狀態等待的是什么呢?其實就是我們今天要介紹的Events(事件),當系統中的Task或ISR設置事件后,等待的任務將轉到Ready狀態。當它成為最高優先級就緒任務時,RTA-OS將選擇運行該Task。
在AUTOSAR操作系統中,事件用于向任務發送信號信息,主要用于為擴展任務提供多個同步點。本文將對什么是事件,如何配置事件以及如何在運行時使用它們。Events的使用場景大致如下圖所示。
2. Events配置
正常在應用中可配置的Events的最大數量取決于硬件,而Events需要配置的內容包括:名字、至少一個Task使用及Event mask。
設置事件時,必須同時指定任務。因此,例如,如果為名為Task1的任務設置名為Event0的事件,則這對任務Task2的Event0沒有影響。
2.1 定義等待任務
在使用中,當我們聲明某個Task需要等待一個Event時,系統將默認該任務為擴展任務,等待事件的擴展任務通常會自動啟動(等待的時間滿足后),并且任務永遠不會終止。當任務開始執行時,RTA-OS將清除它擁有的所有事件。
3. 如何使用Event
3.1 等待事件
任務的等待事件需要調用WaitEvent(EventMask) API,具體等待的EventMask需要關聯到提前聲明的內容。
WaitEvent()將事件作為其唯一參數。執行調用時,有兩種可能:
1)事件暫未發生。這種情況下該Task會進入等待狀態,RTA-OS會運行Ready狀態中優先級最高的Task。
2)事件已經發生。在這種情況下,任務將保持在運行狀態,并將在WaitEvent()調用之后的語句中繼續執行。
3.1.1 等待單一事件
要等待單個事件,只需將事件掩碼名稱傳遞給API調用。下面示例顯示了任務如何使用等待事件。
#includeTASK(ExtendedTask){ ... WaitEvent(Event1);/*TaskenterswaitingstateinAPIcallif Event1hasnothappened*/ /*WhenEvent1isset,ExtendedTaskresumeshere*/ ... }
在AUTOSAR操作系統中,為處于掛起狀態的任務設置事件是非法的。實際上,這意味著等待事件的任務結構通常是一個等待事件的有限循。
3.1.2 等待多個事件
因為AUTOSAR OS事件只是一個位掩碼(Bit Mask),所以用戶可以通過按位設置一組位掩碼,同時等待多個事件。
當任務等待多個事件時,當等待的任何一個事件發生時,它將恢復。當從等待多個事件恢復時,將需要確定發生了哪些事件。
#includeTASK(ExtendedTask){ EventMaskTypeWhatHappened; while(true){ WaitEvent(Event1|Event2|Event3); GetEvent(Task1,&WhatHappened); if(WhatHappened&Event1){ /*TakeactiononEvent1*/ ... }elseif(WhatHappened&Event2){ /*TakeactiononEvent2*/ ... }elseif(WhatHappened&Event3){ /*TakeactiononEvent3*/ ... } } }
在AUTOSAR-OS中,提供了GetEvent()的API,我們可以通過該API獲知哪個事件已完成。
3.1.3 擴展任務的死鎖
雖然AUTOSAR操作系統在關鍵部分的資源互斥中提供了免于死鎖的自由,但在構建具有可能死鎖的事件的系統時,仍不會受到保護。如果我們有相互設置和等待事件集的擴展任務,則兩個(或更多)任務可能正在等待僅由其他正在等待的任務設置的事件。當然,即使存在死鎖擴展任務,系統中的基本任務也不可能死鎖。
下面的樣例展示了擴展任務的死鎖:
#includeTASK(Task1) { while (1) { WaitEvent(Ev1); /* Never reach here - DEADLOCKED with Task2! */ SetEvent(Task2,Ev2); } } TASK(Task2) { while (1) { WaitEvent(Ev2); /* Never reach here - DEADLOCKED with Task1! */ SetEvent(Task1,Ev1); } }
OS配置不獲取哪些任務或ISR設置了事件,只獲取哪些任務可以等待事件。因此,RTA-OS不可能靜態地確定擴展任務是否會死鎖。采用下面的設計方法可能會避免類似問題:
?僅使用基本任務;
?分析代碼,以表明在所有SetEvent()或WaitEvent()對的傳遞閉包上沒有循環等待事件。
3.2 設置事件
通過SetEvent() API 來設置事件。
SetEvent()調用有兩個參數,一個任務和一個事件掩碼。對于指定的任務,SetEvent()調用設置事件掩碼中指定的事件。該調用不會為共享事件的任何其他任務設置事件。
在調用SetEvent()時,可以按位或多個事件掩碼來同時為任務設置多個事件。
無法為處于掛起狀態的任務設置事件。因此,在設置事件之前,必須確保任務未掛起。您可以使用GetTaskState()API調用來實現這一點,但請注意,當為優先級高于調用方的任務調用此函數時,可能存在競爭條件。調用方可以在對API的調用和對結果的評估之間被搶占,并且被請求的任務的狀態在中間時間內可能已經改變。
當擴展任務正在等待的任何一個事件被設置時,擴展任務將從等待狀態移動到就緒狀態。
如下任務顯示了任務如何設置事件:
#includeTASK(Task1) { TaskStateType TaskState; /* Set a single event */ SetEvent(Task2, Event1); /* Set multiple events */ SetEvent(Task3, Event1 | Event2 | Event3); ... /* Checking for the suspended state */ GetTaskState(Task2,&TaskState); if (TaskState != SUSPENDED) { SetEvent(Task2, Event1); } ... TerminateTask(); }
多個任務可以同時等待同一個事件,然而從上面例子可以看出,事件沒有廣播機制,換句話說,不能通過調用一個API告訴所有等待的任務該事件已經發生。
此外,也可以通過Alarms及調度表來設置事件。
3.2.1通過Alarm設置事件
Alarm可用于定期激活不終止的擴展任務。每次Alarm到期時,都會設置該事件。等待事件的任務隨后準備好運行。
3.2.2 通過帶有到期點的調度表設置事件
調度表上的到期點可用于編程(a)非終止狀態的擴展任務的定期激活。每次處理到期點時,都會設置事件。等待事件的任務隨后準備好運行。
3.3 清除Events
可以通過Task或者ISRs來設置Event,但是Event只能被其owner清除。
#includeTASK(ExtendedTask){ EventMaskType WhatHappened; ... while( WaitEvent(Event1|Event2|Event3)==E_OK ) { GetEvent(Task1, & WhatHappened); if(WhatHappened & Event1 ) { ClearEvent(Event1); /* Take action on Event1 */ ... } else if( WhatHappened & (Event2 | Event3 ) { ClearEvent(Event2 | Event3); /* Take action on Event2 or Event3*/ ... } } }
當某個任務等待某個事件,該事件發生,在后面時序再次對同一個事件調用WaitEvent()時,由于該事件仍處于Set狀態,會立即返回。因此,在再次調用等待事件前需要將之前已發生事件清除。
清除事件時調用ClearEvent API,被清除后的狀態必須與事件掩碼關聯起來。
當某個任務被掛起時,其所擁有的Event將被自動清除。
3.4 用基礎任務模擬擴展任務
基礎任務只能在任務執行的開始或結束時同步。
如還有其他同步節點需要時,可以通過event機制來實現。然而,擴展任務較基礎任務占用資源更多,在資源限制的系統中,只能通過使用基礎任務來進行 同步。
例如,如果任務構建為狀態機(例如,使用C switch語句),則可以設置狀態變量,發出TerminateTask()調用并等待重新激活。如下樣例代碼顯示了如何實現這一點。
#include/* Create a "State" variable that remains in scope between task activations */ uint8 State; TASK(Task1) { switch (State) { case 0: /* Synchronization point 0. */ State = 1; break; case 1: /* Synchronization point 1. */ State = 2; break; case 2: /* Synchronization point 2. */ State = 0; break; } TerminateTask(); }
4.本文總結
Event是用于同步的實體,可用于擴展任務的等待內容;
同一個Event可被不同的Task引用;
Event不具有廣播機制,即無法將信息通知所有等待該Event中的任務;
Tasks,ISRs及調度表都可以設置Events。
如果時效性在系統中很重要,則所有擴展任務(任何等待事件的任務)的優先級必須低于基本任務。
審核編輯:湯梓紅
-
操作系統
+關注
關注
37文章
6856瀏覽量
123437 -
AUTOSAR
+關注
關注
10文章
363瀏覽量
21625 -
事件
+關注
關注
0文章
12瀏覽量
9945 -
ISR
+關注
關注
0文章
38瀏覽量
14451
原文標題:RTA OS系列介紹03-Event
文章出處:【微信號:汽車電子嵌入式,微信公眾號:汽車電子嵌入式】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論