儲存對映--mmap
儲存對映
- 使一個磁碟檔案與儲存空間中的一個緩衝區相對映。
- 當從緩衝區中取資料,就相當於讀檔案中的相應位元組。
- 將資料存入緩衝區,則相應的位元組就自動寫入檔案。
使用這種方法,首先應通知核心,將一個指定檔案對映到儲存區域中。這個對映工作可以通過mmap函式來實現。不通過IO。直接操作記憶體,效率更高。
mmap函式
函式原型
#include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
引數分析
- addr : 建立對映區的首地址,由Linux核心指定。使用時,直接傳遞NULL。
- length : 對映長度。
-
prot
: 對映區許可權。
- PROT_READ:只讀。
- PROT_WRITE:只寫。
- PROT_READ | PROT_WRITE:可讀可寫。
- 其它引數不常用,參照手冊。
-
flags:
標誌位引數(常用於設定更新物理區域、設定共享、建立匿名對映區).
- MAP_SHARED:會將對映區所做的操作反映到物理裝置(磁碟)上。
- MAP_PRIVATE: 對映區所做的修改不會反映到物理裝置。
- MAP_ANON:匿名對映,不需要已存在的檔案進行對映。fd傳-1,只能用於親緣程序間。
- fd: 用來建立對映區的檔案描述符。
- offset: 起點的偏移量,必須是4K的整數倍。因為對映至少一頁,比如5000位元組的檔案,對映記憶體也是2頁大小,不會正好是5000.
Note
使用MAP_SHARED的時候,要注意開啟檔案的許可權>=對映區許可權。因為如果檔案沒有寫許可權,對映區有寫許可權,那麼對映區是無法寫入檔案的,這和MAP_SHARED的目的相反。如是MAP_PRIVATE就沒有此要求。
另外,檔案開啟許可權起碼要是可讀的,如果不可讀,那麼怎麼讀取資料對映到記憶體呢?
返回值
- 成功呼叫返回對映的地址。
- 失敗時返回MAP_FAILED,即void * (-1)。設定errno.
munmap函式
函式原型:
#include <sys/mman.h> int munmap(void *addr, size_t length);
此函式較為簡單,釋放對映區,首地址為addr,長度為length.
- 成功的時候返回0.
- 失敗返回-1且置errno。
應用例項
實現程序間的通訊,寫程序將一份檔案對映到記憶體,並且每秒寫入(覆蓋寫入)不同的字串,讀程序一直去讀。
寫程序:
struct Person{ char name[30]; int num; }; int main(int argc, char const* argv[]) { //開啟檔案,作為對映 int fd = open("memTest2.txt", O_RDWR); //int fd = open("memTest2.txt", O_RDWR); int length = sizeof(struct Person); ftruncate(fd, length); printf("fd=%d\n", fd); //對映 struct Person* mem = (struct Person*)mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mem == MAP_FAILED) { perror("mmap err"); return -1; } printf("對映區地址:%0x\n", mem); int num = 1; while (1) { mem->num = num++; sprintf(mem->name, "I am a Person%03d", mem->num); sleep(1); } //釋放 munmap(mem, length); close(fd); return 0; }
讀程序:
struct Person{ char name[30]; int num; }; int main(int argc, char const* argv[]) { //開啟檔案,作為對映 int fd = open("memTest2.txt", O_RDWR); int length = sizeof(struct Person); printf("fd=%d\n", fd); //對映 struct Person* mem = (struct Person *)mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if(mem == MAP_FAILED) { perror("mmap err"); return -1; } printf("對映區地址:%0x\n", mem); while (1) { printf("name=%s,num=%d\n", mem->name,mem->num); sleep(1); } //釋放 munmap(mem, length); close(fd); return 0; }