mmap函數
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
參數:
void *addr
建立映射區的首地址,由Linux內核指定,所以我們直接傳遞NULL。也就是說雖然這是一個參宿但是并不需要我們傳遞,當建立好映射區以后映射區的首地址將以返回值返回。size_t length
建立映射區的大小,一般由創建映射區的文件的大小int prot
用來表示映射區的權限(讀,寫,讀寫,執行,對于執行一般是操作系統調用)。PROT_READ
PORT_WRITE
PROT_READ | PROT_WRITE
int flags
標志位參數,可以通過設置標志位來決定對映射區的修改是否反應到磁盤上。MAP_SHEARD
會將映射區所做的修改反映到物理設備上MAP_PRIVATE
映射區所做的修改不會反映到物理設備
int fd
用來建立映射區的文件描述符off_t offset
映射文件的偏移,用于截取文件的一部分建立映射區(4K的整數倍)
返回值:
成功返回創建映射區的首地址。失敗返回MAP_FAILED
ftruncate
用來擴展文件大小
關閉映射區:
int munmap(void *addr, size_t length);
第一個參數必須是映射區的首地址,長度可以變化
成功返回0,失敗返回-1
例如:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<string.h>int main()
{int fd = open("mmap1file",O_CREAT | O_RDWR | O_TRUNC ,0644);if(-1 == fd){perror("open error");exit(1);}if(-1 == ftruncate(fd, 128)) {perror("ftruncate error:");exit(1);}char *p = mmap(NULL, lseek(fd,0,SEEK_END), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if(MAP_FAILED == p){perror("mmap error:");exit(1);}strcpy(p,"Hello mmap!");close(fd); //關閉文件if(-1 == munmap(p,128)){perror("munmap error:");exit(1);}return 0;
}
注意事項
- 可以用
malloc
創建大小為0 的堆空間,并且可以free, 不可以創建大小為0 的映射區 - 如果文件是以只讀方式打開的就不能改變文件大小
- 如果文件是以只讀方式打開,那么不能將映射區設置為
MAP_SHARED
,但是可以將映射區設置為MAP_PRIVATE
- 如果文件以只寫方式打開,將無法建立映射區,錯誤信息為
Permission denied
,因為創建映射區的過程中其實有一次隱含的讀操作 - 創建映射區的權限要小于等與文件的權限
- 偏移量必須是頁(4K)的整數倍
- 因為
mmap
容易出錯,所以一定要保留mmap的返回值,并通過perror
輸出錯誤信息 - 關閉映射區的時候
munmap
的第一個參數必須是映射區的首地址 - 建立映射區以后文件即使關閉也不影響,如果是
MAP_SHARED
的話仍舊會修改磁盤文件
利用共享內存在父子進程之間通信
用于通信的時候我們創建一個臨時文件,成功創建映射區以后將文件關閉不再使用。
具體的方法是:
- 創建一個文件
- 使用
ftruncate
函數改變文件大小 - 使用
unlink
函數刪除目錄項(創建臨時文件) - 建立映射區
- 關閉文件
在父子進程間通信時MAP_SHARED
指的是共享同一個映射區,MAP_PRIVATE
指的是不共享映射區,父子進程分別占用
匿名映射
因為正常mmap
函數必須依賴一個文件,雖然這個文件沒有存在的必要,因此我們需要open
、ftruncate
、unlink
、close
比較麻煩。因此我們可以使用匿名映射較為方便地創建映射區。
int *p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
len
可以根據我們的需要修改大小。
MAP_ANONYMOUS
表示匿名通信,可以簡寫為MAP_ANON
需要注意的是MAP_ANONYMOUS
只能夠在Linux
系統中使用,在其他類Unix
系統中不可以使用,在其他系統中使用字符設備文件/dev/zero
int fd = open("/dev/zero", O_RDWR);
p = (int*)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
mmap無血緣關系進程通信
同一個文件創建的是一個映射區,因此如果我們想要在沒有血緣關系,就需要通過同一個文件來建立映射區
strace 可執行文件
追蹤程序里面所使用的系統調用有哪些
其實Linux系統對文件的操作是通過mmap進行的