UNP(卷2:進程間通信)—— 第12章:共享內存區介紹

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

“不再涉及內核”:指 進程不再通過執行任何進入內核的系統調用來彼此傳遞數據。顯然,內核必須建立允許各個進程共享該內存區的內存映射關係,然後一直管理該內存區


通常的客戶服務器消息傳遞,需複製四次:



共享內存區,只需複製兩次:



mmap、munmap、msync

mmap函數把一個文件或者一個Posix共享內存區對象映射到調用進程的地址空間

使用該函數有三個目的

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

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

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

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
                                                                                 // 返回:若成功則爲被映射區的起始地址,若出錯則爲MAP_FAILED
其中,addr 可以指定描述符 fd 應被映射到的進程內空間的起始地址它通常被指定爲一個空指針,這樣告訴內核自己去選擇起始地址。無論哪種情況,該函數的返回值都是描述符fd所映射到內存區的起始地址。

len 是映射到調用進程地址空間的字節數。它從被映射文件開頭起第offset個字節處開始算。offset通常設置爲0。


內存映射區的保護由 prot參數 指定


flags 參數:

MAP_SHARED MAP_PRIVATE 這兩個標誌必須指定一個,並可有選擇地或上 MAP_FIXED。

1,如果指定了MAP_PRIVATE,那麼調用進程對被映射數據所作的修改只對該進程可見,而不改變其底層支撐對象(或者一個文件對象,或者一個共享內存區對象)。 

2,如果指定了MAP_SHARED,那麼調用進程對映射數據所做的修改對於共享該對象的所有進程可見,而且確實改變了其底層支撐對象。

3、從移植性上考慮,MAP_FIXED不應該去指定。如果沒有指定該標誌,但是addr不是一個空指針,那麼如何處置取決於實現。不爲空的addr通常被當作有關該內存區應如何具體定位的線索。 可移植的代碼應把addr指定成一個空指針,並且不指定MAP_FIXED


父子進程之間共享內存區的方法之一是,父進程在調用fork前先指定MAP_SHARED調用mmap。

mmap返回後,fd參數可以關閉,該操作對於由mmap建立的映射關係沒有影響。


munmap 函數:爲從某個進程的地址空間刪除一個映射關係。

#include <sys/mman.h>

int munmap(void *addr, size_t length);
                                       // 返回:若成功則爲0,出錯-1
其中 addr 參數是由 mmap返回的地址,len是映射區的大小。再次訪問這些地址將導致向調用進程產生一個SIGSEGV信號(當然這裏假設以後的mmap調用並不重用這部分地址空間)。

如果被映射區是使用 MAP_PRIVATE 標誌映射的,那麼調用進程對它所作的變動都會被丟棄掉。


msync函數:

內核的虛擬內存算法保持內存映射文件(一般在硬盤上)與內存映射區(在內存中)的同步,前提是它是一個MAP_SHARED內存區。這就是說,如果我們修改了處於內存映射到某個文件的內存區中某個位置的內容,那麼內核將在稍後的某個時刻相應的更新文件。然而有時候我們希望確信硬盤上的文件內容與內存映射區中的內容一致,於是調用msync來執行這種同步

#include <sys/mman.h>

int msync(void *addr, size_t length, int flags);
                                                   // 返回:若成功則爲0,出錯-1

其中addr 和len 參數通常指代內存中的整個內存映射區,不過也可以指定該內存區的一個子集。

flags 參數:


MS_ASYNC 和 MS_SYNC 這兩個常值中必須指定一個,但不能都指定。

它們的差別是:一旦寫操作已由內核排隊入列,MS_ASYNC 即返回,而MS_SYNC則要等到寫操作完成後才返回。如果還指定了 MS_INVALIDATE,那麼與其最終副本不一致的文件數據的所有內存中副本都失效。後續的引用將從文件中取得數據。

不是所有文件都能進行內存映射,例如,試圖把一個訪問終端或套接字的描述符映射到內存將導致mmap返回一個錯誤。這些類型的描述符必須使用read和write(或它們的變體)來訪問。


匿名內存映射:指定mmap的flags參數:MAP_SHARED | MAP_ANON


/dev/zero 內存映射










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章