天天看點

嵌入式OS入門筆記-以RTX為案例:七.RTX的程序間通訊(一)嵌入式OS入門筆記-以RTX為案例:七.RTX的程序間通訊(一)

嵌入式OS入門筆記-以RTX為案例:七.RTX的程序間通訊(一)

上一篇筆記講了一下RTX的三種排程機制。可以看到RTX配置下是有并發的,也就是有幾個程式都處于已啟動運作到運作完畢之間,且這幾個程式都是在同一個處理機上運作,但任一個時刻點上隻有一個程式在處理機上運作的情況。實際上并行是會涉及很多問題的,好比如果隻是一個人在幹活那麼他不需要和别人溝通就能完成這個任務,但如果多人同時在幹活(或者是為了同一個目的,或者不是為了同一個目的),如果他們需要共享到一些資源,那就涉及到溝通協調的額外付出了。OS的設計也涉及類似的問題。在進一步讨論一些并發會造成的問題前,我們先介紹一下RTX是如何實作程序與程序間的通訊的。

RTX的程序間通訊主要依賴于四種機制,分别是事件(Event),互斥鎖(Mutex),旗語或信号量(Semaphore),和郵箱(Mailbox)。前三種機制側重程序間的同步,郵箱則側重程序間的資料通訊。這裡先讨論事件和互斥鎖,信号量和郵箱請參見下一篇。

我們先考慮如下一個場景,A程序運作到一定時間後,需要等待一個外設的信号(或者别的資料),它可以選擇忙綠等待(busy-waiting):

...
while(something_unfinished){}
...
           

當something_unfinished由真變為假時,A程序才可以跳出這個while循環。此前它一直是在忙等,CPU執行的指令很可能是NOP(一條彙編指令,什麼也不做,空轉)。是以實際上是浪費CPU資源。這樣的做法有些時候是有必要的,但絕大時間,更好的做法是使用類似中斷的設計,先讓A程序暫停,以執行其他的程序,等到something finishes再來通知A程序。

設計程序間的通訊的一部分功能就是避免忙等,但更多的是為了解決一下并發性問題。下面我們具體看看事件和互斥鎖機制。

1.事件(Event)

簡單說來,就是每一個程序有16個标示,每個标示隻有1和0的狀态。程序可以設定其他程序的标示,也就是說通知其他程序,某事件發生了。在滿足一定條件的後,就可以激活這個程序。

相應的事件标示儲存在TCB(程序控制塊)上,如果程序需要等待事件,将會進入WAIT_OR或者WAIT_AND狀态,當事件條件滿足之後,就會重新進入READY,等待排程器去排程。

具體說來,當程序執行如下幾個操作,就會進入等待狀态,直到标示狀态滿足:

os_evt_wait_and(U16wait_flags,U16timeout);

和事件等待,第一個參數是一個十六位的二進制數,哪一位是1就代表程序需要等待那一位的事件标示。第二個參數設定的是最大等待時間,以time tick value為機關,程序隻會等待到最大等待事件,然後恢複為就緒狀态等待排程。如果設定為0xFFFF,則最大等待時間為無窮,也就是隻會等待事件标示狀态滿足wait_flags的要求。

os_evt_wait_or(U16wait_flags,U16timeout);

與事件等待,參數意義與和事件等待相同。

這兩個操作的差别在于(其實應該比較一目了然)對于和事件等待而言,所有标示都滿足了,程序才會被喚醒,對于與事件等待而言,任一标示狀态滿足了就會喚醒程序。 舉個例子:

os_evt_wait_and (0xABCD, 0xFFFF);

os_evt_wait_or (0xABCD, 0xFFFF);

第一個語句的話,程序會等待15,13,11,9,8,7,6,3,2,0位(0xABCD)的标示全部被設為1時才會被喚醒,而對第二個語句而言,15,13,11,9,8,7,6,3,2,0位中的任一一位标示被設為1,程序就會被喚醒。

這兩個語句傳回類型都是OS_RESULT。結果有兩種,一是,OS_R_EVT,意思就是事件條件滿足了(與或和),程序會被喚醒而且标志會被清零,另外一種就是OS_R_TMO,程序等待超越了最大等待時間。

設定事件标示執行以下操作(一般是别的程序):

os_evt_set(0xABCD,taskID);

這就會設定程序D指定程序的事件标示。

os_evt_clear(0xABCD,taskID);

類似地,這個用于清理程序ID指定程序的事件标示。

另外簡單提一下,中斷(在RTX中,中斷不算程序)也可以設定這些事件标示的,而且RTX提供了一個更加輕量的設定語句:

isr_evt_set (U16 event_flags, OS_TID task_id);

2.互斥鎖(Mutex)

如果第一次接觸互斥鎖,那這個概念其實還不容易解釋。總的來說,就是一個鎖,他基本的運用就是一個程序需要先取鑰匙去解鎖(有且隻有一把鑰匙,且取鑰匙和還鑰匙的過程不可被中斷),完成特定任務後還鑰匙以便其他程序可以繼續使用。

一個簡單的應用場景是,整棟房子隻有一個公共廁所(共享資源),要使用廁所就要去前台拿鑰匙(互斥鎖),用完廁所後需要還鑰匙給前台。這樣做的原因就是為了保證對某些資源的互斥操作(例如你要避免多個程序同時讀寫一塊記憶體區域)。一些複雜的話題我們遲點再讨論,先簡單說說RTX的互斥鎖怎麼用。

首先要聲明一個互斥鎖,互斥鎖在RTX中是一個結構體。

OS_MUT mutexID;

然後需要初始化。

os_mut_init (mutexID);

然後當你需要取鑰匙(要獨占某資源)時:

os_mut_wait (mutexID, timeout );

這個會向RTX申請要獨占這個互斥鎖,如果沒有别的程序占用,那麼目前程序就會獲得互斥鎖,如果有别的程序占用,目前程序就會進入 WAIT_MUT狀态,直到互斥鎖占用被解除,或者timeout,timeout的設定和事件中timeout的設定一樣。(0xFFFF為無窮,以timer tick value為機關)。解除後進入就緒狀态等待排程。

類似事件,這個也會傳回OS_RESULT: OS_R_MUT(互斥鎖被其他程序占用),OS_R_TMO(超過最大等待時間),OS_R_OK(成功占用互斥鎖)。

要解除互斥鎖占用,調用:

os_mut_release (mutexID);

注意,隻有占用了互斥鎖的程序才能成功解除互斥鎖占用!如果程序本身沒有占用互斥鎖,這個語句不會改變什麼。

3.小結

這些隻是粗淺地大概記下了一些關于事件和互斥鎖的用法。我們以後再讨論另外兩種機制的用法,一些具體的例子,和其他更深刻的涉及并發的問題。