mmap

 
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char** argv)
{
  int fd;
  
  fd=open(argv[1],O_CREAT|O_RDWR|O_TRUNC,0777);
  lseek(fd,100,SEEK_SET);
  write(fd,"",1);
  close( fd );
  
  return 0;
}
这个函数的作用是创建一个大小为100的文件
执行如下:
./test /home/nsl/myprogram/shmfile
运行此函数,结果得到的文件还真的是大小为100,可是不知道该如何理解,从程序上看不过是往99的位置处写了个'\0'而已,可是我看有人说文件大小和文件内容完全无关,在linux系统中由inode记录文件长度和文件中的块数,如果读到最后一块,说明文件结束
我看了一下apue,对mmap的介绍不是很好理解,所以从网上找了点资料
本人下面所写的东西也是在理解这篇文章的东西上写的,但是毕竟自己重写一遍会好理解一些,所以不辞辛劳
为什么要用共享内存呢?为什么不直接把数据写到一个文件里,再从一个文件读呢?
因为mmap和memcpy快啊,cpu时间大概是普通的read/write的一半(在linux中)
当要进行重复的数据传输操作时,用这个好
mmap
void* mmap(void* addr,size_t len,int prot,int flags,int fd,off_t offset)
addr:指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成
len:映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起
prot:指定共享内存的访问权限,可取如下值: PROT_READ,PROT_WRITE,PROT_EXEC,PROT_NONE
flags:包括MAP_SHARED,MAP_PRIVATE,MAP_FIXED,其中MAP_SHARED,MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用
fd:即将映射到进程空间的文字描述子,一般由open()返回,同时fd可以为-1,表示匿名映射,用于亲缘关系的进程之间
offset:一般设置为0,表示从文件的开头处开始映射
返回值:为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址
如需参考资料,请输命令:man mmap
可以看出来,文件mmap以后,磁盘文件就不再是普通的文件,其实这个普通的文件描述字已经可以关掉,对这个文件的访问已经可以像访问普通内存一样去访问了,其实数据在没有解除映射之前,这些数据也是不写到磁盘文件中去的。
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

typedef struct
{
  char name;
  int    age;
}people;

int main(int argc, char** argv) // map a normal file as shared mem:
{
  int fd,i;
  people *p_map;
  char temp;
  
  fd=open(argv[1],O_CREAT|O_RDWR|O_TRUNC,0777);
  //O_CREAT:没有就创建的形式打开
  //O_RDWR:读写的方式打开
  //O_TRUNC:如果文件存在且以写方式打开,则清空文件内容和文件长度
  printf( "sizeof(people) = %d\n",sizeof(people));
  lseek(fd,sizeof(people)*5-1,SEEK_SET);
  write(fd,"",1);
  p_map = (people*) mmap( NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0 );
  close( fd );//映射完了之后磁盘文件就可以关掉了
  temp = 'a';
   for(i=0; i<10; i++)
  {
        (*(p_map+i)).name = temp ;
    temp += 1;
    ( *(p_map+i) ).age = 20+i;
  }
  printf( " initialize over \n ");
  sleep(10);
  munmap( p_map, sizeof(people)*10 );
  printf( "umap ok \n" );
  
  return 0;
}
注意,mmap那一句其实得到的实际的地址,然后对地址进行(people *)强制类型转换,使得这个的p_map指针就像malloc过一样,指向了一块内存的起始地址
把这个编译为test1
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

typedef struct
{
  char name;
  int    age;
}people;

int main(int argc, char** argv)  
{
  int fd,i;
  people *p_map;

  fd=open( argv[1],O_CREAT|O_RDWR,0777 );
  p_map = (people*)mmap( NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
   for(i = 0;i<10;i++)
  {
                printf( "name: %c age %d;\n",(*(p_map+i)).name, (*(p_map+i)).age );
  }
  munmap( p_map,sizeof(people)*10 );
  
  return 0;
}
把这个程序编译为test2
执行情况:
./test1 /home/nsl/myprogram/shm_file & (转入后台运行)
./test2 /home/nsl/myprogram/shm_file
在test1还没munmap之前:
name: a age 20;
name: b age 21;
name: c age 22;
name: d age 23;
name: e age 24;
name: f age 25;
name: g age 26;
name: h age 27;
name: i age 28;
name: j age 29;
在test1被munmap之后:
name: a age 20;
name: b age 21;
name: c age 22;
name: d age 23;
name: e age 24;
name:  age 0;
name:  age 0;
name:  age 0;
name:  age 0;
name:  age 0;
可见,在共享文件只有5个people那么大的时候映射10个people没有返回错误,应为,映射文件时按页的,也就说要映射的剩余大小小于一页的时候,统统分配一夜,所以映射10个也没有错,并且进行的数据的操作也没有返回错误,因为对地址的操作还在那一页当中,如果超出页,那就会出错
当munmap时,那就把数据写入到磁盘文件中去了,因为磁盘文件的大小只有5个people,所以对共享内存数据进行了截断,所以test2再去读,就只有5个people的大小了
所以,映射的大小最好不要超过文件的大小
另外
页的大小是多少,怎么查看?不会,故写了个程序
#include <unistd.h>
int main()
{
  int a = getpagesize();
  printf ( "%d\n",a);
}
得到的返回时4096,我的页大小是4096字节
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值