存儲映射I/O能將一個磁盤文件映射到存儲空間中的一個緩衝區上,於是可以用對緩衝區的讀寫代替對磁盤文件的讀寫,這樣就可以在不使用read和write的情況下執行I/O。爲了實現這種功能,應首先將一個給定的文件映射到一個存儲區域中,這由mmap函數實現。
注:子進程能夠通過fork繼承父進程的存儲映射區。
mmap函數
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flag, int fd, off_t off);
返回值:若成功,返回映射區的起始地址; 若出錯,返回MAP_FAILED
參數
addr
用於指定映射存儲區的起始地址。通常將其設置爲0,表示由系統選擇該起始地址,並由函數返回。
fd
指定要被映射文件的描述符。在文件映射到地址空間之前,必須先打開該文件。len
指定要映射的字節數。off
要映射字節在文件中的起始偏移量。prot
指定映射存儲區域的保護要求。如下圖所示prot 說明 PROT_READ 映射區可讀 PROT_WRITE 映射區可寫 PROT_EXEC 映射區可執行 PROT_NONE 映射區不可訪問 可將proc參數指定爲PROT_NONE,也可以指定爲其他三項的任意組合的按位或。要注意,對於指定映射區域的保護要求不能超過文件open模式訪問權限。例如,文件是隻讀打開的,就不能對映射區指定PROT_WRITE。
flag
下圖展示了一個存儲映射文件
圖中“起始地址”是mmap的返回值,映射存儲區位於堆和棧之間(具體取決於實現)
下面是flag參數可選的值,它們影響着映射存儲區的多種屬性:
每種實現可能還有其它的一些標誌值,具體參見系統手冊。MAP_FIXED
返回值必須等於參數addr。這不利於可移植性,所以不推薦使用。如未指定此標誌,且addr不爲0,則系統只把addr作爲一個建議,但是不保證會使用該地址。MAP_SHARED
這一標誌描述了進程對映射區所進行的存儲操作的配置。該標誌指定存儲操作修改映射文件,也就是存儲操作相當於對該文件的write。
注意:必須指定本標誌或下一個標誌(MAP_PRIVATE),但不能同時指定。MAP_PRIVATE
本標誌說明,對映射區的存儲操作導致該映射文件的一個私有副本。所有後來對該映射區的引用都是引用該副本。任何修改隻影響該副本,而不影響源文件。
off和addr通常被要求是虛擬存儲頁長的整數倍,該長度可通過使用參數_SC_PAGE_SIZE的sysconf函數獲得。
相關信號
- SIGSEGV
只是進程試圖訪問對它不可用的存儲區。如果映射區指定爲只讀,那麼試圖向其中寫入數據就會產生該信號 SIGBUS
如果映射區的某部分在訪問時已不存在,則產生該信號。
munmap函數
當進程終止時,會自動解除存儲映射區的映射,或者調用munmap函數也可以解除映射區。關閉被映射的文件描述符並不能解除映射區。munmap並不會使映射區的內容寫入到磁盤文件中,對於MAP_SHARED區的數據,會由內核在某個時刻將其寫入磁盤文件;而對於MAP_PRIVATE區的修改會被丟棄。
#include <sys/mman.h>
int munmap(void *addr, size_t len)
//返回值:成功,返回0;出錯,返回-1
;
mprotect函數
調用該函數可以修改一個現有映射的權限。
#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);
//返回值:成功,返回0;出錯,返回-1
msync函數
將被修改的頁沖洗到被映射的文件中。
#include <sys/mman.h>
int msync(void *addr, size_t len, int flags);
//返回值:成功,返回0;出錯,返回-1