段 哲
(中國船舶重工集團公司第七二二研究所 武漢 430079)
在計算機和信息技術高速發展的今天,計算機和計算機技術大量地應用在我們的日常生活中,廣泛應用的嵌入式系統便是其中的一種。在PC市場已趨于穩定的今天,嵌入式系統的發展速度正在加快,嵌入式系統不僅廣泛應用于工業、交通、通信、科研、醫療衛生、等日常生活等領域,而且很多應用于各種航天、軍工與醫療等高安全的工作需求的工作環境中,系統出現問題可能帶來巨大的經濟損失,甚至危及人的生命。另一方面由于航天、軍工與醫療等工作環境中的特殊性,要求的設備必須滿足一些環境或者電磁兼容或者可靠性的要求。嵌入式Linux系統具有高實時性和高可靠性的特點,因而越來越被廣泛地應用在上述領域。
在應用中,Linux系統下的通信無疑是值得研究的重點和難點。本文比較了在Linux系統下進程之間相互通信的幾種IPC(InterProcess Communication)技術,同時結合C語言的一些語言特性,針對采用Linux幀緩沖設備的嵌入式系統給出了一個有效的通信機制。該實現對含有需要實時處理的多個功能模塊進行分時控制,在犧牲系統資源的基礎上,保證了系統的高實時性和高可靠性,從而滿足了各種航天、軍工與醫療等高安全的工作需求的工作環境的要求。
把從一個進程連接到另一個進程的一個數據流稱為管道,它是UNIX系統IPC的最古老形式,并且所有UNIX系統都提供此種通信機制。管道有下面的特點:
1)半雙工:即數據只能在一個方向上流動,需要通信時,需要建立起兩個管道;
2)只能在具有公共祖先的進程之間使用,即只能用于父子進程或者兄弟進程之間;
3)管道對于管道兩端的進程而言,就是一個文件但它不是普通的文件,它不屬于某種文件系統,而是自立門戶,單獨構成一種文件系統,并且只存在于內存中。
信號是為了使進程獲得某項重要的通知而發送給它的重要事件。這時進程必須立即停止當前的工作,轉而處理該信號。每一個信號都用一個整數代表信號的類型。這些信號定義在系統文件/usr/include/asm/signal.h中,我們在日常使用Linux的過程中經常接觸到信號操作,比如當某個程序正在運行時為了終止程序的運行按下Ctrl-C鍵,或使用Kill命令把該進程殺掉,實際上都是使用了信號作進程間通信。當系統捕獲了某信號時,就會響應該信號指定的動作,系統才對它進行處理,沒有發出信號的進程就處于等待狀態。
信號是軟件層次上對中斷機制的一種模擬,在實際應用中,一個進程收到一個信號與處理器收到一個中斷請求可以說是一樣的。通常來說信號的生命周期分為以下四個階段:
1)信號產生:信號事件的發生主要有兩個來源:硬件來源和軟件來源;
2)信號注冊:信號在進程中注冊指的是使進程知道需要處理某個信號;
3)信號注銷:信號在進程中注銷指進程等待處理某個信號,且該信號沒有被進程阻塞,則在運行相應的信號處理函數前,進程把信號從未決信號鏈中卸載;
4)信號處理:進程注銷信號后,立即執行相應的信號處理函數,執行完畢后,信號的本次發送對進程的影響徹底結束。
管道應用的一個重大限制是它沒有名字,因此,它只能用于具有親緣關系的進程間通信;FIFO不同于管道之處在于它提供一個路徑名與之關聯,以FIFO的文件形式存在于文件系統中,這樣,即使與FIFO的創建不存在親緣關系的進程,只要可以訪問該路徑,就能夠彼此通過FIFO相互通信。值得提出的是FIFO嚴格遵循先進先出(First In First Out),對管道及FIFO的讀總是從開始處返回數據。
共享內存可以說是最有效的進程間通信方式。最顯而易見的好處就是效率高,進程可以直接讀寫內存,而不需要任何數據的復制。對于管道和消息隊列等通信方式,需要在內核和用戶空間進行四次數據復制,而共享內存只復制兩次數據:一次從輸入文件到共享內存區,另一次從共享內存區到輸出文件。Linux從2.2內核開始支持多種共享內存方式,如mmap()系統調用等。
消息隊列就是一個消息的鏈表??梢园严⒖醋鲆粋€記錄,具有特定的格式以及特定的優先級,對消息隊列有寫權限的進程可以向其中按照一定的規則添加新消息。對消息隊列有讀權限的進程則可以從消息隊列中讀走消息。
由于嵌入式系統自身的優勢,有多種通信方式,結合實際項目的需要,所以提出了本文的設計方案。
傳統的設計機制是基于圖1所示的各功能模塊的系統組成結構。該系統包括了顯示模塊、串口模塊、網絡模塊、鍵盤模塊、數據處理模塊,以及主控制模塊6個模塊。其他類型的嵌入式系統都可在此基礎上進行縮減或擴展,其基本的軟件設計思路是完全相同的。系統的一致性為研究和開發統一的軟件實現機制提供了廣闊的應用空間。
在很多嵌入式系統設計中,通常是在主函數Main(*argv,*argn)中,創建多個線程,進行數據的交互,從而滿足實時多任務的處理。雖然我們可以使用互斥量來解決線程之間互相破壞的問題,但當一個互斥量已經被別的線程鎖定后,如果一直沒有被解鎖,等待它的線程將一直被掛著,程序就陷入死鎖狀態,這時,所有線程都因等待互斥量而被掛起,它們中任何一個都不可能恢復運行,程序無法繼續運行下去。這樣的設計模式會導致各模塊的錯綜復雜的糾纏,使系統各功能模塊具有極高的耦合性。一旦某個線程出現問題,就會導致系統癱瘓,甚至死機現象,造成不可估量的后果。
由于很多嵌入式系統應用于各種航天設備、軍工設備等高安全需求的環境中,系統出現問題可能帶來巨大的經濟損失,甚至危及人的生命;而一個不合理的實現機制很難甚至不可能保證其行為,尤其是現在的系統越來越復雜,實現的功能越來越多,包含的模塊越來越多,該問題就越來越嚴重。只有系統在一個合理的實現機制下運行,才能保證系統的可靠性與穩定性。
在進程間通信采用信號、消息機制,可以很好地處理具有多模塊功能的嵌入式系統的實時要求,多任務需求,從而滿足更復雜功能的設備的需求。
系統采用中央集中控制策略,主控制模塊執行各種決策控制(參見圖1),主動向外圍設備(子模塊)寫信息,而采用信號(軟中斷)的方式接收外圍設備(子模塊)發送的信息。在主控制模塊與外圍設備(子模塊)之間存在如圖2所示的數據交互界面。

圖2 主控制模塊與外圍設備的數據交互界面
各模塊通過進程間通信即消息、信號機制,完成設備所需的功能。
其中主控制模塊設定為父進程,其它模塊為子進程。利用fork()函數可以創建新的子進程。利用Linux多進程地址空間的獨立性,使中央控制模塊與各外圍設備控制模塊相互隔離,以免相互影響。但是在實現時必須注意多進程的同步問題,解決這個問題的辦法是在程序中設置信號量,允許進程通過檢測和設置它的值來實現同步,保證在此期間其他進程不能進行類似的操作。通過Linux系統的信號機制,給中央控制模塊與各外圍設備控制模塊提供實時通信,提高CPU的處理效率。通過Linux系統的消息機制,給中央控制模塊與各外圍設備控制模塊提供數據通信。通過消息隊列可靠地傳遞各模塊發送或接收的數據。
新機制采用的多進程分配空間各自獨立,空間消耗上比多線程大,但與整個系統的高安全性和高可靠性相比,我們可以在系統資源允許的情況下,以犧牲系統資源為代價,來滿足各種航天設備、軍工設備等高安全需求的環境要求。所以本文提出的方案是適宜的。
為了更好的說明問題,在本例中我們打開兩個子進程,進行多進程操作與進程間通信演示,軟件框圖如圖3所示。

圖3 多進程通信框圖
if(pid1==0)
{
int times=0;
if(signal(SIGPATOCH1,sig_usr)==SIG_USR)
{
printf("can'tcatch SIGPATOCH1");
return;
}
for(;;)
{
sleep(3);
times++;
memset(buf,0,100);
sprintf(buf,"msgtype1,msginfo%d",times);
msgwrite(ctop_queueid,buf,strlen(buf),1);
kill(getppid(),SIGCH1TOPA);
}
}
子進程2完成功能:每隔5秒向父進程發一個消息,然后發信號SIGCH2TOPA,父進程收到該信號后讀取該消息隊列,實現代碼如下:
if(pid2==0)
{
int times=0;
for(;;)
{
sleep(5);
times++;
memset(buf,0,100);
sprintf(buf,"msg type 2,msginfo%d",times);
msgwrite(ctop_queueid,buf,strlen(buf),2);
kill(getppid(),SIGCH1TOPA);
}
}
父進程實例代碼:
if(signo==SIGCH1TOPA)
{
memset(buf,0,100);
sprintf(buf,"%s",ch_to_par_msg.mtext);
strcat(buf,tempbuf);
msgwrite(ptoc_queueid,buf,strlen(buf),1);
//取消SIGPATOCH1信號的發送,
kill(pidsub1,SIGPATOCH1);
}
else if(signo==SIGCH2TOPA)
{
memset(buf,0,100);
sprintf(buf,"%s",ch_to_par_msg.mtext);
strcat(buf,tempbuf);
msgwrite(ptoc_queueid,buf,strlen(buf),1);
//取消SIGPATOCH1信號的發送,
kill(pidsub2,SIGPATOCH2);
}
}
本文利用嵌入式系統提供的進程通信機制:信號、消息隊列,給出了一種適合于經典嵌入式系統的系統實現,并給出了一些簡單范例代碼;該機制在系統資源允許的情況下,以犧牲系統資源為代價來保障系統的高安全性和高可靠性,從而滿足各種航天設備、軍工設備等高安全需求的環境中要求,并在實際應用中取得了良好的實現效果。
[1]W.RICHARD STEVENS BILL FENNER.UNIX網絡編程[M].楊繼張,譯.北京:清華大學出版社,2006,1
[2][美]W.Richard Stevens Stephen A.Rago.UNIX環境高級編程[M].第二版.尤晉元,張亞英,戚正偉,譯.北京:人民郵電出版社,2006,5
[3]于明儉,陳向陽,方漢.Linux程序設計權威指南[M].北京:機械工業出版社,2001,4
[4]楊水清,張劍,施云飛,等.ARM嵌入式系統開發技術詳解[M].北京:電子工業出版社,2008,11
[5][美]K.Wall,M.Watson,M.Whitis,et al.GNU/Linux編程指南[M].王勇,王一川,林花軍,等譯.北京:清華大學出版社,2000,7