mmap映射区和shm共享内存的区别总结

转自:https://blog.csdn.net/hj605635529/article/details/73163513

linux中的两种共享内存。一种是我们的IPC通信System V版本的共享内存,另外的一种就是我们今天提到的存储映射I/O(mmap函数)

 

在说mmap之前我们先说一下普通的读写文件的原理,进程调用read或是write后会陷入内核,因为这两个函数都是系统调用,进入系统调用后,内核开始读写文件,假设内核在读取文件,内核首先把文件读入自己的内核空间,读完之后进程在内核回归用户态,内核把读入内核内存的数据再copy进入进程的用户态内存空间。实际上我们同一份文件内容相当于读了两次,先读入内核空间,再从内核空间读入用户空间。

 

 

 Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改,mmap()系统调用使得进程之间可以通过映射一个普通的文件实现共享内存。普通文件映射到进程地址空间后,进程可以向访问内存的方式对文件进行访问,不需要其他系统调用(read,write)去操作。

mmap图示例:

 

mmap系统调用介绍

 
  1. void *mmap(void *addr, size_t length, int prot, int flags,

  2. int fd, off_t offset);

  • 1
  • 2
  • 1
  • 2

 

这就是mmap系统调用的接口,mmap函数成功返回指向内存区域的指针,图上的进程的地址空间的开始地址就是mmap函数的返回值,失败返回MAP_FAILED。

addr,某个特定的地址作为起始地址,当被设置为NULL,系统会在地址空间选择一块合适的内存区域。

length说的是内存段的长度。

prot是用来设定内存段的访问权限。

prot参数说明
PROT_READ内存段可读
PROT_WRITE内存段可写
PROT_EXEC内存段可执行
PROT_NONE内存段不能被访问

flags参数控制内存段内容被修改以后程序的行为。

flags参数说明
MAP_SHARED进程间共享内存,对该内存段修改反映到映射文件中。提供了POSIX共享内存
MAP_PRIVATE内存段为调用进程所私有。对该内存段的修改不会反映到映射文件
MAP_ANNOYMOUS这段内存不是从文件映射而来的。内容被初始化为全0
MAP_FIXED内存段必须位于start参数指定的地址处,start必须是页大小的整数倍(4K整数倍)
MAP_HUGETLB按照大内存页面来分配内存空间

fd参数是用来被映射文件对应的文件描述符。通过open系统调用得到。offset设定从何处进行映射。

mmap使用注意事项:

利用mmap进行非血缘进程间通信代码:

 

 
  1. #include<stdio.h>

  2. #include<stdlib.h>

  3. #include<unistd.h>

  4. #include<fcntl.h>

  5. #include<sys/types.h>

  6. #include<sys/stat.h>

  7. #include<sys/mman.h>

  8. #include<string.h>

  9.  
  10. struct STU

  11. {

  12. int age;

  13. char name[20];

  14. char sex;

  15. };

  16.  
  17. int main(int argc,char *argv[]) //这个进程用于创建映射区进行写。

  18. {

  19. if(argc != 2)

  20. {

  21. printf("./a,out file");

  22. exit(1);

  23. }

  24.  
  25. struct STU student = {10,"xiaoming",'m'};

  26.  
  27. int fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0644);

  28. if(fd < 0)

  29. {

  30. perror("open");

  31. exit(2);

  32. }

  33. ftruncate(fd,sizeof(struct STU)); //文件拓展大小。

  34.  
  35. struct STU *p = (struct STU*)mmap(NULL,sizeof(struct STU),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//创建一个结构体大小的共享映射区。共享映射区我们可以当做数组区看待。

  36. if(p == MAP_FAILED)

  37. {

  38. perror("mmap");

  39. exit(3);

  40. }

  41. close(fd); //关闭不用的文件描述符。

  42. while(1)

  43. {

  44. memcpy(p,&student,sizeof(student));

  45. student.age++;

  46. sleep(1);

  47. }

  48. int ret = munmap(p,sizeof(student));

  49. if(ret < 0)

  50. {

  51. perror("mmumap");

  52. exit(4);

  53. }

  54.  
  55. return 0;

  56. }

 
  1. #include<stdio.h>

  2. #include<stdlib.h>

  3. #include<unistd.h>

  4. #include<fcntl.h>

  5. #include<sys/types.h>

  6. #include<sys/stat.h>

  7. #include<sys/mman.h>

  8.  
  9. struct STU

  10. {

  11. int age;

  12. char name[20];

  13. char sex;

  14. };

  15.  
  16. int main(int argc,char *argv[]) //这个进程读

  17. {

  18. if(argc != 2)

  19. {

  20. printf("./a,out file");

  21. exit(1);

  22. }

  23.  
  24.  
  25. int fd = open(argv[1],O_RDONLY,0644);

  26. if(fd < 0)

  27. {

  28. perror("open");

  29. exit(2);

  30. }

  31.  
  32. struct STU student;

  33.  
  34. struct STU *p = (struct STU*)mmap(NULL,sizeof(struct STU),PROT_READ,MAP_SHARED,fd,0);

  35. if(p == MAP_FAILED)

  36. {

  37. perror("mmap");

  38. exit(3);

  39. }

  40. close(fd);

  41. int i = 0;

  42. while(1)

  43. {

  44.  
  45. printf("id = %d\tname = %s\t%c\n",p->age,p->name,p->sex);

  46. sleep(2);

  47. }

  48. int ret = munmap(p,sizeof(student));

  49. if(ret < 0)

  50. {

  51. perror("mmumap");

  52. exit(4);

  53. }

  54.  
  55. return 0;

  56. }

代码截图:

 



分析:因为只创建一个结构体大小的共享内存,后面写入的数据把前面写入的数据覆盖了。

 

shm调用介绍:参见上一篇博客

http://blog.csdn.net/hj605635529/article/details/67636526

 

shm图示例:

 

(1)通过int shmget(key_t key, size_t size, int shmflg);在物理内存创建一个共享内存,返回共享内存的编号。
(2)通过void *shmat(int shmid, constvoid shmaddr,int shmflg);连接成功后把共享内存区对象映射到调用进程的地址空间
(3)通过void *shmdt(constvoid* shmaddr);断开用户级页表到共享内存的那根箭头。
(4)通过int shmctl(int shmid, int cmd, struct shmid_ds* buf);释放物理内存中的那块共享内存。

 

总结mmap和shm:
1、mmap是在磁盘上建立一个文件,每个进程地址空间中开辟出一块空间进行映射。
而对于shm而言,shm每个进程最终会映射到同一块物理内存。shm保存在物理内存,这样读写的速度要比磁盘要快,但是存储量不是特别大。
2、相对于shm来说,mmap更加简单,调用更加方便,所以这也是大家都喜欢用的原因。
3、另外mmap有一个好处是当机器重启,因为mmap把文件保存在磁盘上,这个文件还保存了操作系统同步的映像,所以mmap不会丢失,但是shmget就会丢失。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值