嵌入式OS入門筆記-以RTX為案例:八.RTX的進程間通訊(二)

來源:互聯網
上載者:User

標籤:arm   os   rtx   嵌入式開發   

嵌入式OS入門筆記-以RTX為案例:八.RTX的進程間通訊(二)

 

RTX的進程間通訊主要依賴於四種機制,分別是事件(Event),互斥鎖(Mutex),旗語或訊號量(Semaphore),和郵箱(Mailbox)。前三種機制側重進程間的同步,郵箱則側重進程間的資料通訊。這次講一下訊號量和郵箱。

 

1.訊號量(Semaphore)

 

1.簡介

訊號量其實是一個很抽象的作業系統原語,它最早由荷蘭電腦科學家Dijkstra提 出,用於解決多項資源的分配問題。實際上訊號量的適用範圍非常廣,可以很好地解決很多問題。簡單說來,訊號量有三個部分,第一部分就是一個代幣容器(一個 整形變數),記錄著可用的資源數,第二部分就是取用資源(P或者proberen,嘗試的荷蘭語)的操作,第三個就是還回資源(V或者verhogen, 增加的荷蘭語)的操作。當資源數量為0時,任何取用資源的操作都會被阻斷,直到資源數量增加。剛剛接觸可能會覺得跟互斥鎖有點難區分,因為RTX中訊號量 的相關操作跟互斥鎖基本一致。先看看怎麼使用RTX中的訊號量。

 

類似互斥鎖,首先要聲明一個訊號量結構體。

OS_SEM semID;


然後需要初始化。

os_sem_init (semID,unsignedtoken_count);

這裡與互斥鎖不同的是,你需要指定初始的資源數,token_count,可以是任意非負整數,如果是0,就意味著一開始沒有資源可用。


然後當你需要取用資源時:

os_sen_wait (semID, timeout );

timeout的意義就不具體多說了,跟前面介紹的一致。如果成功取用了資源(token_count大於0),那麼token_count會減一,並且返回OS_R_OK。如果token_count為0,那麼就沒辦法取用資源,那麼這個函數會返回OS_R_SEM,並且進程進入WAIT_SEM狀態。

當你用完了資源,需要返回資源時,(token_count增加1):

os_sem_send (semID);

和互斥鎖不同的是,當前進程不需要擁有資源,也可以調用該服務,去增加資源數!

該服務的中斷版本:

isr_sem_set (semID);

 

2.訊號量和互斥鎖的區別

一般的誤區是,訊號量用於管理多個只能獨享的資源。我們重新考慮上一次提到的情境:整棟房子只有一個公用廁所(共用資源),要使用廁所就要去前台拿鑰匙(互斥鎖),用完廁所後需要還鑰匙給前台。在這種情況下,使用互斥鎖機制肯定沒問題,那麼使用訊號量機制會有問題嗎?

如果所有人(進程)都循規蹈矩,那沒問題。但如果有人沒有去廁所,但也還了一把鑰匙給前台,那會發生什麼事?那就會有兩把鑰匙,通向同一個廁所,如果當前有 人在上廁所,另外一個人也想要上,前台也會給鑰匙給第二個人,那麼就會發生尷尬的情況。這個在使用訊號量時是有可能的,因為當前進程不需要擁有資源,就能 夠os_sem_send!所以哪怕在這種最簡單的情況下,也是很有可能誤用訊號量的。

複雜一點的情況,我們考慮如果有兩個公用廁所,如果使用互斥鎖,那就要聲明並初始化兩個互斥鎖,分別管理兩個廁所。那麼使用訊號量機制,初始化一個os_sem_init (toilet,2);的訊號量會不會有問題呢?如果我們不考慮有人惡意還鑰匙(os_sem_send誤用)的話,好像沒問題,因為訊號量本身就是為了這樣的情境(管理多個獨享資源)而設計的?

實際上,一樣是會有問題的,因為訊號量實際上是不區分資源的,而且也不會記錄資源使用的順序。按照我們的例子,也就是說前台會有兩把相同的鑰匙,任一一把都 可以開啟兩個廁所。假設第一個人去前台拿了一把鑰匙,進了廁所A,然後第二個人去前台拿了第二把鑰匙,實際上第二個人是無法得知,兩個廁所裡面有沒有人, 如果有,是哪一個廁所裡面有人。所以,也很有可能會發生尷尬的情況。

 

總的來說,當多個獨享資源的先後順序無關時(例如,生產者和消費者問題),使用訊號量才比較合適。

或者當進程本身同時是資源的佔用者和釋放者時,使用互斥鎖:

 

OS_MUTmutex;os_mut_init(mutex);.../*Task 1 */   os_mut_wait(mutex,0xFFFF);           // Critical Section   os_mut_release(mutex);... /*Task 2 */   os_mut_wait(mutex,0xFFFF);      // Critical Section   os_mut_release(mutex);...



當資源的釋放者不一定是進程的佔用者時,使用訊號量:

 

OS_SEMsempahore;os_sem_init(semaphore,0);.../*Task 1 - Producer */    os_sem_wait(semaphore,0xFFFF);   // Send the signal.../*Task 2 - Consumer */    os_sem_send(semaphore);  // Wait for signal...


 

3.幾個例子

訊號量的用法實在是太豐富,而且很容易誤用,具體可以參見《The Little Book of Semaphores》和RTX的官方文檔,這裡摘幾個經典的用法(修改過)作為例子:

 

Signaling
os_semsemaphore;__taskvoid task1 (void) {    os_sem_init (semaphore, 0);    while (1) {        Function1();        os_sem_send (semaphore);    }} __taskvoid task2 (void) {    while (1) {        os_sem_wait (semaphore, 0xFFFF);        Function2();    }}

這個用法是用於保證不同函數的調用順序(這是C語言很缺乏的一個特徵),在這個例子裡面,訊號量的作用就是確保在每一次調用Function2之前,Function1都有一次完整的調用。

 

Rendezvous
os_semArrived1, Arrived2;__taskvoid task1 (void) {    os_sem_init (Arrived1, 0);    os_sem_init (Arrived2, 0);    while (1) {        FunctionA1 ();        os_sem_send (Arrived1);        os_sem_wait (Arrived2, 0xFFFF);        FunctionA2 ();    }} __taskvoid task2 (void) {    while (1) {        FunctionB1 ();        os_sem_send (Arrived2);        os_sem_wait (Arrived1, 0xFFFF);        FunctionB2 ();    }}

這個用法是更通用的Signaling用法,目的是讓FunctionA1,functionB1都完成以後,再執行FunctionA2和FunctionB2。

 

Multiplex
os_semMultiplex;__taskvoid task(void){    os_sem_init (Multiplex, 5);    while (1) {        os_sem_wait (Multiplex, 0xFFFF);        Function ();        os_sem_send (Multiplex);    }}

這個用法能保證最多隻有五個進程能夠同時調用Function();

 

更多的例子,請參考上面提到的材料。

 

2.郵箱(Mailbox)

 

1.簡介

郵箱在RTX中往往是用於在進程間傳輸大段資料。簡單說來,一個郵箱就是一個使用者定義長度的隊列。隊列的每一個單元都是4bytes長,一個單元可以直接保 存資料(32位),或者儲存一個指標(地址),指向另外一段資料。用郵箱的一個問題就是要使用者手動分配記憶體和回收記憶體。下面先看看有哪些相關操作。

 

首先要建立一個郵箱,

os_mbx_declare(mailbox_name,mail_slots);

在RTL.h中有這個的定義,具體是:

#define os_mbx_declare(name,cnt) U32name [4 + cnt]

也就是說郵箱其實是一個名字為mailbox_name,長度為mail_slots的U32數組。另外注意到,額外的4個slots,是用於管理郵箱的,而不是用來直接儲存資訊的。

 

建立完郵箱後就要初始化這個郵箱:


os_mbx_init (&mailbox_name,sizeof(mailbox_name));


發信:


os_mbx_send(&mailbox,msg_ptr,timeout);


這裡的msg_ptr實際上是一個指標,指向需要發送的資訊,如果郵箱滿了,進程會被阻斷,進入WAIT_MBX狀態,直到有空間才會返回就緒狀態。 timeout的用法和前面的timeout一致。


同樣地,在ISR中有一個相應版本:


isr_mbx_send(&mailbox,msg_ptr);


這會先調用isr_mbx_check(),去檢查郵箱是否已經滿了,如果滿了就會放棄當前的資訊,並且會被陷入os_error();


收信:


os_mbx_wait (&mailbox, &msg_ptr, timeout );


將收到的資訊,存入msg_ptr指向的地址。如果郵箱是空的,進程則會被阻斷,進入WAIT_MBX狀態,直到有新的資訊。


ISR的相應版本為:


isr_mbx_receive(&mailbox,&msg_ptr);



2.BOX記憶體配置

在用郵箱的過程中,會經常涉及到RTX的記憶體配置問題,如果是變長的記憶體配置,malloc() 和 free()這些標準函數可以勝任,但RTX另外提供了一種處理定長記憶體塊的機制-BOX。


這裡大致簡單說一下,具體的用法請參考完整的郵箱例子。


_declare_box(box_name,block_size,block_count);

_init_box(box_name,box_size,block_size);

_alloc_box(box_name);

_calloc_box(box_name);

_free_box(box_name,)


基本上從名字就能知道其意義,和stdlib.h中的標準函數基本對應。


3.一個完整的例子

這個例子源於《RL-ARMUser‘s Guide》,小幅度修改:


os_mbx_declare(MsgBox, 16); /* Declare an RTX mailbox */U32 mpool[16*(2*sizeof(U32))/4 + 3]; /* Reserve a memory for 16 messages */__task void rec_task (void);__task void send_task (void) {    /* This task will send a message. */    U32 *mptr;    os_tsk_create (rec_task, 0);    os_mbx_init (MsgBox, sizeof(MsgBox));    mptr = _alloc_box (mpool); /* Allocate a memory for the message */    mptr[0] = 0x3215fedc; /* Set the message content. */    mptr[1] = 0x00000015;    os_mbx_send (MsgBox, mptr, 0xffff); /* Send a message to a 'MsgBox' */    os_tsk_delete_self ();}__task void rec_task (void) {    /* This task will receive a message. */    U32 *rptr, rec_val[2];    os_mbx_wait (MsgBox, (void**)&rptr,0xffff); /* Wait for the message to arrive. */    rec_val[0] = rptr[0]; /* Store the content to 'rec_val' */    rec_val[1] = rptr[1];    _free_box (mpool, rptr); /* Release the memory block */    os_tsk_delete_self ();}int main (void) {    _init_box (mpool, sizeof(mpool),sizeof(U32));    os_sys_init(send_task);}


3.小結這一部分是RTX中內容很豐富的一部分,簡短的三言兩語也許很難概括清楚,這裡也只是講了一些基本的用法。接下來會分析一些並行會遇到的問題。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.