程式間通訊---共享記憶體

發表於2016-11-21

一、IPC(Inter-Process Communication,程式間通訊)物件的介紹

System V 的IPC物件有共享記憶體、訊息佇列、訊號燈。

程式間通訊---共享記憶體

注意:在IPC的通訊模式下,不管是使用訊息佇列還是共享記憶體,甚至是訊號燈,每個IPC的物件都有唯一的名字,稱為”鍵”(key)。通過”鍵”,程式能夠識別所用的物件。”鍵”與IPC物件的關係就如同檔名稱於檔案,通過檔名,程式能夠讀寫檔案內的資料,甚至多個程式能夠公用一個檔案。而在 IPC的通訊模式下,通過”鍵”的使用也使得一個IPC物件能為多個程式所共用。

二、共享記憶體的介紹

<1>共享記憶體是一種最為高效的程式間通訊方式,程式可以直接讀寫記憶體,而不需要任何資料的拷貝。

<2>為了在多個程式間交換資訊,核心專門留出了一塊記憶體區,可以由需要訪問的程式將其對映到自己的私有地址空間。程式就可以直接讀寫這一塊記憶體而不需要進行資料的拷貝,從而大大提高效率。

<3>由於多個程式共享一段記憶體,因此也需要依靠某種同步機制。

三、共享記憶體的特點

程式間通訊---共享記憶體

四、共享記憶體的操作流程

<1>建立/開啟共享記憶體

<2>對映共享記憶體,即把指定的共享記憶體對映到程式的地址空間用於訪問

<3>撤銷共享記憶體對映

<4>刪除共享記憶體物件

五、相關 API

A.獲取一塊共享記憶體

程式間通訊---共享記憶體

功能:分配一塊共享記憶體

返回值:

呼叫成功返回一個shmid(類似開啟一個或建立一個檔案獲得的檔案描述符一樣);

呼叫失敗返回-1。

引數說明:

<1>key標識共享記憶體的鍵值(就像檔案的標識是檔名):0  / IPC_PRIVATE。

當key的取值為IPC_PRIVATE,則函式shmget()將建立一塊新的共享記憶體;

如果key的取值為0,而引數shmflg中設定了IPC_CREATE這個標誌,則同樣建立一塊新的共享記憶體。

通過這種方式分配的共享記憶體,一般用來親緣關係的程式間通訊。

注意:我們一般是通過ftok這個函式獲取鍵值

功能 : 獲取一個IPC物件的鍵值

引數說明:

pthname就是你指定檔名的路徑(該檔案必須是存在而且可以訪問的),一般情況我們都寫一個目錄

proj_id  : 和pthname一起完成建立鍵值的引數,雖然為int,但是隻有8個位元被使用。一般我們寫一個字元代替。

例如:

案例:

程式間通訊---共享記憶體

執行的結果:

程式間通訊---共享記憶體

<2>size是要建立共享記憶體的長度。所有的記憶體分配操作都是以頁為單位的。所以如果一個程式只申請一塊只有一個位元組的記憶體,記憶體也會分配整整一頁(在i386機器中一頁的預設大小PACE_SIZE = 4096位元組)。

<3>shmflg有效的標誌包括IPC_CREAT 和IPC_EXCL,他們的功能與open()的O_CREAT和O_EXCL相當。

IPC_CREAT      如果共享記憶體不存在,則建立一個共享記憶體,否則直接開啟已存在的
IPC_EXCL        只有在共享記憶體不存在的時候,新的共享記憶體才建立,否則就產生錯誤

例子一:假設鍵值為key,建立一個共享記憶體大小為4k,訪問許可權為066,如果已經存在則返回其標識號

例子二、假設鍵值為key,建立一個共享記憶體大小為1k,訪問許可權為0666,如果已經存在則報錯

B.共享記憶體的對映

程式間通訊---共享記憶體

函式shmat將標識號為shmid共享記憶體對映到呼叫程式的地址空間中。

引數說明:

shmid  :  要對映的共享記憶體區識別符號

shmaddr  :  將共享記憶體對映到指定地址(若為NULL,則表示由系統自動完成對映)

shmflg  :  SHM_RDONLY  共享記憶體只讀

預設0:共享記憶體可讀寫。

返回值 :呼叫成功放回對映後的地址 ,出錯放回(void *)-1;

C.取消共享記憶體與使用者程式之間的對映

程式間通訊---共享記憶體

引數shmaddr是shmat對映成功放回的地址。

注意:當一個程式不再需要共享記憶體段時,它將呼叫shmdt()系統呼叫取消這個段,但是,這並不是從核心真正地刪除這個段,而是把相關shmid_ds結構的shm_nattch域的值減1,當這個值為0時,核心才從物理上刪除這個共享段。

D.控制共享記憶體

程式間通訊---共享記憶體

引數說明:

shmid  共享記憶體標識ID

cmd      IPC_STAT得到共享記憶體的狀態
IPC_SET改變共享記憶體的狀態
IPC_RMID刪除共享記憶體

buf  是一個結構體指標。IPC_STAT的時候,取得的狀態放在這個結構體中。如果要改變共享記憶體的狀態,用這個結構體指定;

程式間通訊---共享記憶體
注意:

1.IPC_RMID命令實際上不從核心刪除一個段,而是僅僅把這個段標記為刪除,實際的刪除發生最後一個程式離開這個共享段時。

2.當cmd為IPC_RMID時,第三個引數應為NULL。呵呵,大部分我們都是這樣做,用這個函式刪除共享記憶體。

案例探究:

執行結果:

程式間通訊---共享記憶體

相關文章