本質:
兩個進程訪問同一個邏輯內存;
直接訪問內存,不用read()/write(),非常方便。
匿名映射文件:
設備 作用 舉例
/dev/zero 永遠輸出0的設備文件 dd if=/dev/zero of=磁盤分區 count=1024 bs=1024
/dev/null 丟棄一切寫入其中數據 cat test > /dev/null
/dev/fd 記錄用戶打開的文件描述符 ls /dev/fd/
頭文件:
sys/mman.h
鏈接庫:
rt
查看:
man shm_overview
ls /dev/shm/
創建:
int shm_open(const char* name,int oflag,mode_t mode);
name:
posix IPC名字。
oflag:
標誌:
標誌 作用
O_CREAT 沒有該對象則創建
O_EXCL 如果O_CREAT指定,但name不存在,就返回錯誤
O_RDONLY 只讀
O_RDWR 讀寫
O_WRONLY 只寫
O_TRUNC 若存在則截斷
mode:
權限。
權限 作用
S_IWUSR 用戶/屬主寫
S_IRUSR 用戶/屬主讀
S_IWGRP 組成員寫
S_IRGRP 組成員讀
S_IWOTH 其他用戶寫
S_IROTH 其他用戶讀
返回值:
-1-------出錯
其他----共享內存描述符
刪除:
int shm_unlink(const char* name);
name:
posix IPC名字。
返回值:
-1——出錯
0——-成功
修改文件大小:
創建新文件時大小爲0,無法映射(存入數據)。
int ftruncater(int fd,off_t length);
fd:
文件描述符。
length:
文件大小。
如果原文件大小比參數length大,超過部分刪除。
返回值:
0——成功
-1——失敗
建立內存映射:
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
start:
映射區的開始地址,一般爲NULL(從可移植考慮)。
如果寫NULL,就是讓系統決定映射區的起始地址。
length:
映射區的長度(以字節爲單位;不足一頁內存按一頁內存處理)。
port:
內存保護標誌。
不能與文件的打開模式衝突(打開爲讀->prot爲讀;打開爲讀寫->prot爲寫或讀寫)。
PROT_EXEC——頁內容可被執行
PROT_READ——頁內容可被讀寫
PROT_WRITE——頁可被寫
PROT_NONE——頁不可訪問
flags:
映射對象類型。
MAP_SHARED——變動共享
MAP_PRIVATE——變動私有
MAP_ANON———匿名內存映射(與MAP_SHARED一起用)
fd:
文件描述符(不能爲套接字和終端的fd)。
-1————匿名內存映射。
offset:
被映射對象內容的起點(偏移量)。
返回值:
MAP_FAILED——失敗
非MAP_FAILED——共享內存地址
刪除內存映射:
int munmap(void* start,size_t length);
start:
映射內存起始地址。
length:
內存大小。
返回值:
0——成功
-1——失敗
注意:
關閉mmap中的文件描述符不能刪除內存映射。
同步(類似fflush):
int msync(void* addr,size_t len,int flags);
addr:
映射內存起始地址。
len:
內存大小。
flags:
同步參數:
MS_ASYNC——異步;調用會立即返回。不等到更新的完成。
MS_SYNC——同步;調用會等到更新完成之後返回。
MS_INVALIDATE——通知使用該共享區域進程,數據以改變;在共享內容更改後,使得文件的其他映射失效。
返回值:
0——成功
-1——失敗
代碼:
創建+修改文件大小:
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
int fd = shm_open(argv[1],O_CREAT|O_RDWR,0644);
ftruncate(fd,atoi(argv[2]));
void* buf = NULL;
if(( buf = mmap(NULL,BUFSIZ,PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){
perror("mmap error\n");
return 1;
}
}
刪除:
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
shm_unlink(argv[1]);
}
讀:
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
int fd = shm_open(argv[1],O_RDONLY,0);
void* buf = NULL;
if(( buf = mmap(NULL,BUFSIZ,PROT_READ,MAP_SHARED,fd,0)) == MAP_FAILED){
perror("mmap error\n");
return 1;
}
printf("%s\n",buf);
munmap(buf,BUFSIZ);
}
寫:
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
int fd = shm_open(argv[1],O_RDWR,0);
void* buf = NULL;
if(( buf = mmap(NULL,BUFSIZ,PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){
perror("mmap error\n");
return 1;
}
strcpy(buf,argv[2]);
munmap(buf,BUFSIZ);
}
親緣進程間的匿名映射:
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char* argv[]){
void* buf = NULL;
if(( buf = mmap(NULL,BUFSIZ,PROT_WRITE|PROT_READ,MAP_SHARED|MAP_ANON,-1,0)) == MAP_FAILED){
perror("mmap error\n");
return 1;
}
if(fork()){
strcpy(buf,argv[1]);
}else{
printf("%s\n",buf);
}
munmap(buf,BUFSIZ);
}