千家信息网

LINUX中的mmap是什么

发表于:2025-12-05 作者:千家信息网编辑
千家信息网最后更新 2025年12月05日,本篇内容主要讲解"LINUX中的mmap是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"LINUX中的mmap是什么"吧!LINUX 中的mmap浅析
千家信息网最后更新 2025年12月05日LINUX中的mmap是什么

本篇内容主要讲解"LINUX中的mmap是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"LINUX中的mmap是什么"吧!



LINUX 中的mmap浅析

一、mmap基本原理和分类
在LINUX中我们可以使用mmap用来在进程虚拟地址空间中分配创建一片虚拟内存地址映射
其可以是
1、文件映射
使用文件内容初始化内存
2、匿名映射
初始化全为0的内存空间(calloc也可以)
下面配图来自UNIX系统编程手册


而对于是否共享又分为
1、私有映射(MAP_PRIVATE)
多进程间数据共享,修改不反应到磁盘实际文件,
私有写时复制实现
2、共享映射(MAP_SHARED)
多进程间数据共享,修改反应到磁盘实际文件中。
那么总结起来有4种组合
1、私有文件映射
多个进程使用同样的物理内存页进行初始化,但是各个进程
对内存文件的修改不会共享,也不会反应到物理文件中,比如
我们LINUX .so动态库文件就采用这种方式映射到各个进程虚拟
地址空间中
2、私有匿名映射
mmap会创建一个新的映射,各个进程不共享,这种使用主要用于
分配内存(malloc分配大内存会调用mmap)。
3、共享文件映射
多个进程通过虚拟内存技术共享同样的物理内存空间,对内存文件
的修改会反应到实际物理文件中,他也是进程间通信(IPC)的一种机制
4、共享匿名映射
这种机制在进行fork的时候不会采用写时复制,父子进程完全共享
同样的物理内存页,这也就实现了父子进程通信(IPC).
下面也是UNIX系统编程手册截图

在/proc/PID/maps下我们可以找到一个当前进程使用mmap创建的映射比如:
379a000000-379a016000 r-xp 00000000 08:03 12320771 /lib64/libgcc_s-4.4.7-20120601.so.1
379a016000-379a215000 ---p 00016000 08:03 12320771 /lib64/libgcc_s-4.4.7-20120601.so.1
379a215000-379a216000 rw-p 00015000 08:03 12320771 /lib64/libgcc_s-4.4.7-20120601.so.1
379a400000-379a4e8000 r-xp 00000000 08:03 9700201 /usr/lib64/libstdc++.so.6.0.13
379a4e8000-379a6e8000 ---p 000e8000 08:03 9700201 /usr/lib64/libstdc++.so.6.0.13
379a6e8000-379a6ef000 r--p 000e8000 08:03 9700201 /usr/lib64/libstdc++.so.6.0.13
379a6ef000-379a6f1000 rw-p 000ef000 08:03 9700201 /usr/lib64/libstdc++.so.6.0.13
对于解释可以参考UNIX系统编程手册如下描述


二、mmap函数原型

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
参数有点多
addr:映射放到哪里(虚拟地址),一般传NULL,让内核自己决定
length:映射的大小(直接),最小是系统页的整数倍(4K)
port:位图掩码
PROT_NONE 不能访问
PROT_READ 可读取
PROT_WRITE 可修改
PROT_EXEC 可执行
非法访问或报SIGSEGV段错误信号
flags:位图掩码
MAP_ANONYMOUS:创建一个匿名映射
MAP_PRIVATE:私有映射
MAP_SHARED:共享映射(注意并不能保证一定实际写入物理磁盘(MSYNC))
MAP_FIXED:addr必须是页对齐地址
其他标示不做解释
fd:映射文件的文件描述符
offset:从文件的哪个位置开始映射,必须是系统页的整数倍(4K)

返回值:
成功返回映射的虚拟内存地址的起始地址,失败返回MAP_FAILED

三、建立匿名映射
1、指针MAP_ANONYMOUS,并且fd指定为0
2、打开/dev/zero文件将文件描述符传递给mmap()
匿名映射会分配初始化全为0的虚拟内存空间

四、其他函数
int msync(void *addr, size_t length, int flags);
用于将kener buffer的数据同步到磁盘
int munmap(void *addr, size_t length);
用于解除映射

五、程序实例
下面我们通过mmap做私有匿名映射来完成一个小的线程间同步问题程序,用这片
内存区域来做线程间通信

点击(此处)折叠或打开

  1. #include

  2. #include

  3. #include

  4. #include

  5. #define uint unsigned int

  6. #define MMSIZE (uint)(1<<23)

  7. #define MSIZE (uint)(1<<20)

  8. #define MPRT (uint)(1<<16)

  9. using namespace std;




  10. class tc

  11. {

  12. private:

  13. uint a;

  14. public:

  15. tc():a(1)

  16. {

  17. ;

  18. }

  19. ~tc()

  20. {

  21. ;

  22. }

  23. void add()

  24. {

  25. a=a+1;

  26. }

  27. void set()

  28. {

  29. a=1;

  30. }

  31. void prt(int i)

  32. {

  33. if(!(i%(MPRT)))

  34. {

  35. cout<<":"<

  36. }

  37. }


  38. };


  39. struct tt

  40. {

  41. tc* p1;

  42. pthread_mutex_t* p2;

  43. };


  44. void* test(void* arg)

  45. {

  46. int i = 0;

  47. tt* s = NULL;

  48. s = (tt*)arg;

  49. int maxloop = 50;

  50. while(maxloop--)

  51. {

  52. i = MSIZE;

  53. pthread_mutex_lock(s->p2);//MUTEX保护临界区

  54. cout<<"Thread:"<

  55. for(;i--;)

  56. {

  57. (s->p1+i)->prt(i);

  58. (s->p1+i)->add();

  59. }

  60. cout<<"\n";

  61. pthread_mutex_unlock(s->p2);//解锁

  62. }

  63. }




  64. int main(void)

  65. {

  66. pthread_t tid[3];

  67. pthread_mutex_t pmut;

  68. tt s1;

  69. tc* p = (tc*)mmap(NULL,MMSIZE,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_PRIVATE,-1,0);//MMAP分配一个匿名私有虚拟内存用于线程间通信

  70. pthread_mutex_init(&pmut,NULL);

  71. s1.p1 = p;

  72. s1.p2 = &pmut;


  73. int i = MSIZE+1;


  74. for(;i--;)

  75. {

  76. (p+i)->set();//初始化所有的a=1

  77. }



  78. for(i=0;i<3;i++)

  79. {

  80. pthread_create(tid+i,NULL,test,(void*)&s1);//建立3个线程

  81. }


  82. for(i = 0;i<3;i++)

  83. {

  84. pthread_join( *(tid+i) , NULL);//堵塞回收线程

  85. }

  86. pthread_mutex_destroy(&pmut);

  87. munmap(p,MMSIZE);


  88. }

同时我们也观察到了线程由于失去CPU而放弃执行其他线程得到CPU继续执行,由于
我们使用MUTEX保护临界区这个数数还是正常进行。最后正常数到了150
Thread:140545405572864 work now!!!
:32:32:32:32:32:32:32:32:32:32:32:32:32:32:32:32
Thread:140545397180160 work now!!! (线程140545405572864 失去CPU线程140545397180160执行)
:33:33:33:33:33:33:33:33:33:33:33:33:33:33:33:33
..................
Thread:140545397180160 work now!!!
:58:58:58:58:58:58:58:58:58:58:58:58:58:58:58:58
Thread:140545405572864 work now!!!(线程140545405572864重新获得CPU)
:59:59:59:59:59:59:59:59:59:59:59:59:59:59:59:59
............
Thread:140545388787456 work now!!!
:150:150:150:150:150:150:150:150:150:150:150:150:150:150:150:150

到此,相信大家对"LINUX中的mmap是什么"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0