mmap系统调用是将一个打开的文件映射到进程的用户空间,mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。
我们的程序中大量运用了mmap,用到的正是mmap的这种“像访问普通内存一样对文件进行访问”的功能。实践证明,当要对一个文件频繁的进行访问,并且指针来回移动时,调用mmap比用常规的方法快很多。
下面介绍mmap函数原型如下:
#include
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
addr:指定为文件描述符fd应被映射到的进程空间的起始地址。它通常被指定为一个空指针,这样告诉内核自己去选择起始地址。一般默认为NULL。
length:是映射到调用进程地址空间中的字节数,她从被映射文件开头offset个字节处开始算。
prot:负责保护内存映射区的保护。常用值是代表读写访问的PROT_READ | PROT_WRITE.当然还包括数据的执行(PROT_EXEC)、数据不可访问(PROT_NONE)
flags:flags常用值有MAP_SHARED或MAP_PRIVATE这两个标志必须选一个,并可以选上MAP_FIXED。如果指定了,那么调用进程对被映射数据所做的修改只对该进程可见,而不该变其底层支撑对象。如果指定了,那么调用进程对被映射数据所作的修改对于共享该对象的所有进程都可见,而且确实改变了其底层支撑对象。
参数fd为映射文件的描述符,offset为文件的起点,默认为0.
下面看一个实例:父子进程共享4字节匿名区
#include
3 #include
4 #define N 10
5 int main ()
6 {
7 int i,sum,fd;
8 int *result_ptr = mmap(NULL,4,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS,fd,0);
9 // int pid=fork();
10 int pid=vfork();
11 if(pid==0)
12 {
13 for(sum=0,i=1;i<=N;i++)
14 sum+=i;
15 *result_ptr = sum;
16
17 }else
18 {
19 wait(0);
20 printf("result=%d\n",*result_ptr);
21 }
22 return 0;
23
24 }
***@wuyaalan:~/code/kernel$ gcc -o mmap1 mmap1.c
***@wuyaalan:~/code/kernel$ ./mmap1
result=55
但是如果把fork换为vfork时,运行时会出现段错误,分析了下
***@wuyaalan:~/code/kernel$ gcc -o mmap1 mmap1.c
***@wuyaalan:~/code/kernel$ ./mmap1
段错误
***@wuyaalan:~/code/kernel$ gcc -g -rdynamic mmap1.c
***@wuyaalan:~/code/kernel$ gdb ./mmap1
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /home/yuyunchao/code/kernel/mmap1...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/yuyunchao/code/kernel/mmap1
Program received signal SIGSEGV, Segmentation fault.
0x080484d7 in main ()
结果是访问了无效的内存。