曹鵬
(解放軍國際關系學院,江蘇 南京 210039)
進程間通信(IPC)指的是至少兩個進程間傳送數(shù)據(jù)或者信號的一些技術和方法,進程是計算機系統(tǒng)分配資源的基本單位,每個進程都有自己的一部分獨立的系統(tǒng)資源,彼此是隔離的。為了能使不同的進程互相訪問資源并進行協(xié)調工作,才有了進程之間的通信。
操作系統(tǒng)中進程間傳遞的信息量有多有少,因此根據(jù)進程通信時信息量大小的不同,可以將進程通信劃分為兩大類型,一種類型主要用于傳遞進程之間同步、互斥、終止、掛起等控制信息的傳遞,由于進程互斥與同步交換的信息量較少,并且每次通信傳遞的信息量固定且效率較低,因此稱這兩種通信方式為低級通信方式,主要方式有信號量。另一種類型在進程間以較高的效率傳送大量數(shù)據(jù),被稱為高級通信方式,主要方式有管道,共享內存和消息隊列。下面對這四種通信方式進行簡單的論述。
信號量也叫信號燈,是一個確定的二元組(S,Q),其中S是個具有非負初置的整形變量,表示的是臨界資源的實體。信號量的值有以下兩種情況:
1)代表可用資源的數(shù)量,此時Q 的隊列為空。
2)代表由于等待此種資源而被阻塞的進程的數(shù)量,也就是Q隊列中進程的個數(shù)。
信號量的值僅能由P、V操作進行改變,其中p操作和v操作是不可中斷的程序段,稱為原語操作,它是典型的同步機制之一。每執(zhí)行一次P操作表示分配一個該類資源給執(zhí)行P操作的進程,因此P操作將信號量的值減1,當信號量的值小于0時,表示已經(jīng)沒有這類資源可供分配了,所以請求資源的進程將被阻塞而被插入到Q的等待隊列當中。此時,信號量的絕對值等于Q隊列中進程的個數(shù),即等待分配該類資源的進程數(shù)。執(zhí)行一次V操作意味著進程釋放出一個該類可用資源,因而V操作是將信號量的值加1。因信號量的值小于等于0表示在該信號量的等待隊列中有請求該類型而被阻塞的進程,因而應把該信號量等待隊中的隊首的進程喚醒,即進程的狀態(tài)由阻塞狀態(tài)變?yōu)榛顒泳途w狀態(tài)。
信號量的創(chuàng)建:Linux系統(tǒng)中使用semget(key,nSemes,flag)來創(chuàng)建一個信號量,key是標識信號量的關鍵字,nSemes表示創(chuàng)建信號量的個數(shù),flag表示為信號量存取權標志與建立標志。
信號量的操作:Linux系統(tǒng)中采用semop(semid,sops,nsops)來實現(xiàn)對信號量的操作,semid為關鍵字值,由semget返回得來,第二個參數(shù)是指向將要操作的數(shù)組的指針,nsops為數(shù)組sops的大小。
管道是Linux支持的最初Unix IPC形式之一,當兩個進程利用管道進行通信時,發(fā)送信息的進程稱為寫進程,接收信息的進程稱為讀進程。管道通信方式的中間介質就是文件,通常稱這種文件為管道文件.它就像管道一樣將一個寫進程和一個讀進程連接在一起,實現(xiàn)兩個進程之間的通信。寫進程通過寫入端(發(fā)送端)往管道文件中寫入信息,讀進程通過讀出端(接收端)從管道文件中讀取信息。管道具有如下特點:
1)管道是半雙工的,數(shù)據(jù)只能向一個方向流動,數(shù)據(jù)只能由寫的一方向讀得一方流動。
2)單獨構成一種獨立的文件系統(tǒng):管道對于管道兩端的進程而言,就是一個文件,成為管道文件,但它不屬于某種文件系統(tǒng),而是自立門戶,單獨構成一種文件系統(tǒng),并且只存在與內存中。
3)數(shù)據(jù)的讀出和寫入:管道建立時,通信兩端的任務都是被固定了的,也就是說,一端只能用于讀,而另一端只能用于寫,寫入的內容每次都添加在管道緩沖區(qū)的末尾,并且每次都是從緩沖區(qū)的頭部讀出數(shù)據(jù)。
消息隊列的基本思想是:系統(tǒng)管理一組消息緩沖區(qū),并稱之為消息緩沖池,其中每個消息緩沖區(qū)存放一條消息。消息實際上就是一組信息。當一個進程要發(fā)送消息時,首先向系統(tǒng)申請一個消息緩沖區(qū),寫入消息后將其連接到接受進程PCB所指示的消息隊列。接受進程在適當?shù)臅r候從其消息隊列中取得消息,并立即釋放該消息緩沖區(qū),交回給系統(tǒng)管理。
消息隊列就是一個消息的鏈表。就是把消息看作一個記錄,并且這個記錄具有特定的格式以及特定的優(yōu)先級。對消息隊列有寫權限的進程可以按照一定的規(guī)則添加新消息;對消息隊列有讀權限的進程則可以從消息隊列中讀出消息。
Linux采用消息隊列的方式來實現(xiàn)消息傳遞。這種消息的發(fā)送方式是:發(fā)送方不必等待接收方檢查它所收到的消息就可以繼續(xù)工作下去,而接收方如果沒有收到消息也不需等待。這種通信機制相對簡單,但是應用程序使用起來就需要使用相對復雜的方式來應付了。新的消息總是放在隊列的末尾,接收的時候并不總是從頭來接收,可以從中間來接收。
Linux中定義了一個名為msgbuf的數(shù)據(jù)結構來表示消息,并利用MSGGET()來創(chuàng)建一個消息隊列,然后返回這個消息隊列的標識號,然后調用MSGSND()向一個消息隊列發(fā)送一個消息,接收進城通過MSGRCV()來從一個消息隊列中收到一個消息。在通信雙方進行通信的過程中,系統(tǒng)可以利用MSGCTL()在消息隊列上執(zhí)行指定的操作,更具參數(shù)的不同和權限的不同,可以執(zhí)行檢索、刪除等得操作。
共享的消息隊列是一個臨界資源,針對同一消息隊列的諸發(fā)送和接收進程必須保證互斥進入,這種進程間的同步和互斥是由系統(tǒng)提供的系統(tǒng)調用自動實現(xiàn)的,所以用戶在使用時不需要再考慮它們之間的同步關系,非常方便。
除上述幾種通信方式之外,Linux還提供了正文段,也就是程序段的共享,當若干進程需要對公共數(shù)據(jù)區(qū)中的數(shù)據(jù)進行頻繁操作時,共享內存的通信方式是一種很有用的通信機制,而且是以一種效率較高的進程通信機制。其基本思想是:系統(tǒng)管理一組共享內存控制塊,當用戶程序進程需要使用共享內存段時,使用SHMGET()系統(tǒng)調用申請一個共享內存段,系統(tǒng)位置分配存儲空間和建立有關的數(shù)據(jù)結構,并返回該共享內存段的標識符shmid,然后系統(tǒng)調用SHMAT()將由標識符shmid標識的共享內存段附加到進程地址空間,一旦將一個共享內存段連接到進程邏輯地址空間后,進程可以像訪問其私有數(shù)據(jù)段一樣存取該共享內存段中的數(shù)據(jù)。當不在使用共享內存時,由系統(tǒng)調用SHMDT()將由參數(shù)定位的共享內存段脫離調用進程的數(shù)據(jù)段。在此期間,可以使用系統(tǒng)調用SHMCTL()查詢由shmid標識的共享內存段的狀態(tài)和設置有關參數(shù),對共享內存段進行控制。
共享內存通信與消息緩沖通信有很多類似之處:都是使用一個id來標識一個IPC目標,通過使用 GET(msgget,shmget)來建立一個IPC目標,都要進行權限檢查等來實現(xiàn)通信。不同點是:共享內存一旦附接后就作為進程地址空間的一部分提供給進程使用對于該共享內存的讀寫操作如同對進程私有的緩沖區(qū)一樣。操作系統(tǒng)不再關心進程間是如何使用這個共享內存,更無法進行干預。
如果用戶傳遞的信息較少。或是需要通過信號來觸發(fā)某些行為,信號量不失為一種簡捷有效的進程間通信方式。但若是進程間要求傳遞的信息量比較大或者進程間存在交換數(shù)據(jù)的要求,就需要考慮高級通信機制。無名管道簡單方便。但局限于單向通信的工作方式,并且只能在創(chuàng)建它的進程及其子孫進程之間實現(xiàn)管道的共享。有名管道雖然可以提供給任意關系的進程使用,但是由于其長期存在于系統(tǒng)之中,使用不當容易出錯.所以普通用戶一般不建議使用。
消息緩沖可以不再局限于父子進程,而允許任意進程通過共享消息隊列來實現(xiàn)進程間通信,并由系統(tǒng)調用函數(shù)來實現(xiàn)消息發(fā)送和接收之間的同步,從而使得用戶在使用消息緩沖進行通信時不再需要考慮同步問題,使用方便,但是信息的復制需要額外消耗CPU的時間,不適宜于信息量大或操作頻繁的場合。共享內存針對消息緩沖的缺點改而利用內存緩沖區(qū)直接交換信息,無須復制,快捷、信息量大是其優(yōu)點。但是共享內存的通信方式是通過將共享的內存緩沖區(qū)直接附加到進程的虛擬地址空間中來實現(xiàn)的。
不同的進程通信方式有不同的優(yōu)點和缺點。因此,對于不同的應用問題,要根據(jù)問題本身的情況來選擇進程間的通信方式。
[1]史杏榮,楊壽寶.操作系統(tǒng)原理與實現(xiàn)技術[M].北京:中國科學技術大學,1997.
[2]陸靜,胡明慶,幾種進程通信方法的研究和比較[J].福建電腦,2007.
[3]Tanenbaum.Modern Operating Systems[M].2009年.
[4]W.Richard Stevens.UNIX高級環(huán)境編程[M].北京:機械工業(yè)出版社,2000年.