本质:
两个进程访问同一个逻辑内存;
直接访问内存,不用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);
}