共享內存

    共享內存是IPC形式中最快的方式。一旦將這樣的內存區映射到共享它的進程的地址空間,這些進程間數據的傳遞就再也不涉及內核。然而往該共享內存區存放信息或從中取走信息的進程間一般須要某種方式的同步。函數

    實現共享內存的方式:利用mmap函數、使用Posix共享內存區、使用SystemV共享內存區,下面分別介紹。ui

1.1 利用mmap進行內存映射

    做用:open文件以後調用mmap把它映射到調用進程地址空間的某個文件。以後全部的I/O都在內核的掩蓋下完成,只需編寫存取映射區中各個值的代碼便可,而沒必要調用read、write或lseek進行操做。線程

    須要說明的一點:並非全部文件都能進行內存映射,如終端和套接字的描述符不支持內存映射,試圖將其映射到內存將致使mmap返回一個錯誤。這些類型的描述符必須使用read和write(或者相關變體)來訪問。指針

    相關函數:mmap,mumap(刪除共享內存)及msync(用於同步共享內存和文件的內容),下面僅介紹mmap。對象

void *mmap(void *addr, size_t len, intprot, inf flag, off_t offset);進程

返回值:成功返回被映射區的起始地址,失敗返回MAP_FAILED內存

參數說明:get

         addr指定描述符fd應被映射到的進程內空間的起始地址,爲了保證可移植性,一般被指定爲一個空指針,這樣就有內核自行選擇起始地址。cmd

         len參數爲映射到進程地址空間中的 字節數,它從被映射文件開頭的offset個字節處開始算。同步

         prot參數指定了映射內存的讀、寫、執行等相關權限,取值可爲PROT_READ、PROT_WRITE、PROT_EXEC、PROT_NONE(不可訪問)

         flag指示該共享內存的做用效果,一般取爲MAP_SHARED(變量是共享的,調用進程對被映射數據所做的修改對於共享該對象的全部進程可見,並改變了底層支持對象——一般是文件);若是指定爲MAP_PRIVATE,那麼調用進程對被映射數據所作的修改只對該進程可見,同時也不改變底層支持對象;以上兩個標誌必須指定一個,當須要準確解釋addr指向的地址參數時或上MAP_FIXED。

    做用:分別用於把一個文件或一個Posix共享內存區對象映射到調用進程的地址空間,有三種目的:

1)      使用普通文件以提供內存映射I/O(應用最普遍)

2)      使用特殊文件以提供匿名內存映射  

有兩種方法:

4.4BSD提供匿名內存映射,避免了文件的建立和打開。其經過把mmap的flag參數指定成MAP_SHARED|MAP_ANON,把fd參數指定爲-1.忽略offset參數。這樣的內存區被初始化爲0。(由fork或具備親緣關係的線程使用)

SVR4提供了/dev/zero設備文件,open它以後可使用獲得的文件描述符,而後裏面mmap進行內存映射,以後執行關閉便可。這樣的映射保證內存映射區被初始化爲0(可由無親緣關係的進程使用)

3)      使用shm_open以提供無親緣關係進程間的Posix共享內存區

 

    訪問共享內存時,文件大小和內存映射大小能夠不一樣,下面進行訪問狀況的兩點說明:

a)        文件大小等於內存映射區的大小:只能訪問相應大小的共享內存,超出的話會引起SIGSEGV信號

b)        文件大小小於共享內存區的大小:只能訪問文件大小+最後一頁上該對象以遠的那些字節,訪問超過的內存(超過文件大小但小於共享內存大小)時,會引起SIGBUS信號。若想訪問這部份內存,須要增長文件大小,可用lseek或者ftruncate函數調整文件大小。

1.2 POSIX共享內存

         Posix共享內存是由shm_open打開一個Posix IPC名字(也許是在文件系統中的一個文件),所返回的描述符由mmap函數映射到當前進程的地址空間。即涉及如下步驟:

一、  指定一個名字參數調用shm_open,以建立一個新的共享內存區對象或打開一個已存在的共享內存區對象

二、  調用mmap把這個共享內存區映射到調用進程的地址空間

相關函數:

頭文件:#include <sys/mman.h>

建立或打開共享內存區對象:

int shm_open(const char *name, into flag,mode_t mode)  //成功返回非負描述符,若出錯則爲-1,name爲絕對路徑的Posix IPC名字形式

刪除共享內存區對象:

int shm_unlink(const char *name)   //成功返回0,失敗-1

p.s:當調用mmap完成內存映射以後就能夠關閉描述符了,由於已經獲得共享內存區的指針了;以後的操做同mmap。與mmap映射文件實現共享內存基本相似,不一樣的是獲取文件描述符的方式。

1.3 System V共享內存

         SystemV共享內存區在概念上相似與Posix共享內存區。其獲取共享內存區的方式爲先調用shmget,再調用shmat,對於每一個共享內存區,內存維護一個shmid_ds對象

相關函數:

頭文件 #include <sys/shm.h>

1)      建立或打開:

int shmget(key_t key, size_t size, intoflag)   //若成功則爲共享內存區對象,若出錯則爲-1;其中key能夠是ftok函數的返回值,也能夠是IPC_PRIVATE;size指示了共享內存區的大小(以字節爲單位),當實際操做爲訪問一個已存在的共享內存區時,應該爲0,而建立時則應大於0

p.s:shmget並無給調用進程提供訪問該內存區的手段,故須要調用shmat

2)      附加共享內存區到調用進程的地址空間:

void *shmat(int shmid, const void *shmaddr,int flag); //若成功則返回映射區的起始地址,若出錯則爲-1;shmaddr通常取爲0,這樣系統會替調用者選擇地址,這是推薦的的方法(可移植性好),若不爲0的話則附加由shmaddr參數指定的地址,這時還和flag參數有關

斷開共享內存(當使用完後調用):

int shmdt(const void * shmaddr);    //成功返回0,失敗返回-1

p.s:當進程終止時,它當前附接着的全部共享內存區都自動斷接掉。函數並不會刪除共享內存,執行刪除的話須要以參數爲IPC_RMID調用shmdt

3)      控制操做:

int shmctl(int shmid, int cmd, structshmid_ds * buff); //若成功返回0,若出錯爲-1

當cmd取不一樣值時,函數能夠實現三個功能以下:

IPC_RMID:從系統中刪除指定的共享內存,這時buff參數置空

IPC_SET:給所指定的共享內存區設置其shmid_ds結構的如下三個成員:shm_perm.uid,shm_perm.did及shm_perm.mode,它們的值來自buff參數的相應成員。shm_ctime的值也用當前時間替換。

IPC_STAT:獲取所指定共享內存當前的shmid_ds結構

 

與System V消息對了和System V信號量同樣,System V共享內存區也存在特定的系統限制。能夠在共享內存相關manual 文件中查看,如man shmget

相關文章
相關標籤/搜索