mmap/munmap函数
函数原型
#include
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
函数功能
mmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存 地址,对文件的读写可以直接用指针来做而不需要read/write函数。
munmap()用来取消参数start所指的映射内存起始地址,参数length则是欲取消的内存大小。当进程结束或利用exec相关函数来执行其他程序时,映射内存会自动解除,但关闭对应的文件描述符时不会解除映射。
mmap参数说明
addr
mmap函数中如果addr参数为NULL,内核会自己在进程地址空间中选择合适的地址建立映射。如果addr不是NULL,则给内核一个提示,应该从什么地址开始映射,内核会选择addr之上的某个合适的地址开始映射。建立映射后,真正的映射首地址通过返回值可以得到。
len
len参数是需 要映射的那一部分文件的长度。
off
off参数是从文件的什么位置开始映射,必须是页大小的整数倍(在32位体系统结构上通常是4K)。
filedes
filedes是代表该文件的描述符。
prot
prot参数有四种取值:
PROT_EXEC表示映射的这一段可执行,例如映射共享库
PROT_READ表示映射的这一段可读
PROT_WRITE表示映射的这一段可写
PROT_NONE表示映射的这一段不可访问
flag
flag参数有很多种取值,常用的两种如下,其它取值可查看mmap(2):
MAP_SHARED多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修 改,另一个进程也会看到这种变化。
MAP_PRIVATE多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修改,另一个进程并不会看到这种变化,也不会真的写到文件中去。
函数返回值
如果mmap成功则返回映射首地址,如果出错则返回常数MAP_FAILED。
当进程终止时,该进程的映射内存会自动解除,也可以调用munmap解除映射。
munmap成功返回0,出错返回-1。
mmap操作修改hello文件:
yu@ubuntu:~/Linux/211$vi hello
yu@ubuntu:~/Linux/211$cat hello
hello
yu@ubuntu:~/Linux/211$od -tx1 -tc hello
0000000 68 65 6c 6c 6f 0a
h e l l o \n
0000006
mmap.c源码:
/*mmap.c*/
#include
#include
#include
#include
int main()
{
int *p;
int fd = open("hello", O_RDWR);
if(fd < 0){
perror("open hello");
exit(1);
}
/* 将文件映射至进程的地址空间 */
p = mmap(NULL, 6, PROT_WRITE, MAP_SHARED, fd, 0);
if(p == MAP_FAILED){
perror("mmap");
exit(1);
}
/* 映射完后, 关闭文件也可以操纵内存 */
close(fd);
printf("%c\n", p[0]);
p[0] = 'A';
p[1] = '\0';
printf("%c\n", p[0]);
munmap(p, 6);
return 0;
}
编译及执行测试:
yu@ubuntu:~/Linux/211$vi hello
yu@ubuntu:~/Linux/211$cat hello
hello
yu@ubuntu:~/Linux/211$gcc mmap.c
yu@ubuntu:~/Linux/211$./a.out
h
A
yu@ubuntu:~/Linux/211$cat hello
A
yu@ubuntu:~/Linux/211$od -tx1 -tc hello
0000000 41 00 00 00 00 00 0a
A \0 \0 \0 \0 \0 \n
0000007
如上所示,成功修改了hello文件。
注意事项:
* 用于进程间通信时,一般设计成结构体,来传输通信的数据
* 进程间通信的文件,应该设计成临时文件
* 当报总线错误时,优先查看共享文件是否有存储空间
具体通信案例请见(Linux进程共享通信 – mmap实现):
http://blog.csdn.net/y396397735/article/details/50651633