破天网站定制,网站实名审核中心,濮阳网络,wordpress仿知乎前言最近在学习GNU/Linux内核#xff0c;看到mmap的时候书上说#xff1a;mmap/munmap接口函数是用户最常用的两个系统调用接口#xff0c;无论是在用户程序中分配内存、读写大文件、链接动态库文件#xff0c;还是多进程间共享内存#xff0c;都可以看到mmap/munmap的身影…前言最近在学习GNU/Linux内核看到mmap的时候书上说mmap/munmap接口函数是用户最常用的两个系统调用接口无论是在用户程序中分配内存、读写大文件、链接动态库文件还是多进程间共享内存都可以看到mmap/munmap的身影。这句话说的很正确虽然我们日常没有直接使用mmap但是其实我们都间接地使用了mmap/mumap函数。举个例子我们使用动态链接库的时候我们都知道动态链接不会把动态库中的代码整合到目标文件中相反动态库跟目标文件独立。那为什么运行时程序能够获得指定的符号链接这正是mmap的力量程序运行时他将保存在物理内存的动态库的内容(如果物理内存中没有则先加载如内存)映射到自身的进程地址空间这样符号所对应的指令数据便存在了。(通过ldd可获取所依赖的动态库Linux怎么获取到的我怀疑跟ELF文件格式有关待解答)mmapmmap是内存映射文件的方法mmap将一个文件或者其它对象映射进内存。mmap在用户空间映射调用系统中作用很大。mmap()必须以PAGE_SIZE为单位进行映射而内存也只能以页为单位进行映射若要映射非PAGE_SIZE整数倍的地址范围要先进行内存对齐强行以PAGE_SIZE的倍数大小进行映射。头文件函数原型void* mmap(void* addr, size_t length,int prot,int flags,int fd,off_t offset); int munmap(void* start,size_t length);addr: 用于指定映射到进程地址的起始地址为了应用程序的可移植性一般设为nullptrlength: 表示映射到进程地址空间的大小prot: 表示设置内存映射区域的读写属性等flags: 用于设置内存映射的属性例如共享映射、私有映射、匿名映射等fd: 文件句柄如果不是文件映射则置为0offset: 文件映射时的文件偏移量。重复一遍由于GNU/Linux中内存分配是以页为单位的所以length长度不足1页(默认4KB)则按1页来处理。prot参数detailflags参数detail共享内存共享内存Shared Memory顾名思义就是允许两个不相关的进程访问同一个逻辑内存共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。具体来说共享内存就是一段真实存在的物理内存不同进程通过访问和修改该段物理内存最终达到共享内存的目的。PS: 共享内存不提供数据同步机制如一个进程在写过程中另一个进程可以进行读操作和写操作所以需要通过信号量来解决同步问题。创建共享内存函数介绍函数原型如下#include #include /* For mode constants */#include /* For O_* constants */int shm_open(const char *name, int oflag, mode_t mode);int shm_unlink(const char *name);Link with -lrt.shm_open()创建并打开一个新的或现有的POSIX共享内存对象。POSIX共享内存对象实际上是一个句柄它可以被与mmap共享内存相同区域的无关进程使用。shm_unlink()函数的作用是删除先前由shm_open()创建的对象。函数用法int fd shm_open(/shm01, O_CREAT | O_RDWR, 0777);当oflag使用O_CREAT时mode表示创建文件时的权限权限写法跟命令chmod一样(https://www.runoob.com/linux/linux-comm-chmod.html)。open与shm_open区别或许你会问如果是创建一个文件何必使用shm_open呢为什么不使用open理论上来说两个方法可以相互替换。但是很重要的一点是shm_open会将文件创建在/dev/shm目录下该目录下挂载的文件系统格式是tmpfs该目录下的文件也只存储在内存(主存)中。如果你使用open方法在该目录下创建和打开文件其实两者就没有本质区别了。如图所示/dev/shm是tmpfs文件系统进程间通讯实例本测试用例需要依赖googletest测试框架当然读者可以通过分别建立两个项目来实现下述实例实例原理如图所示共享内存创建后保存在真实的物理内存中通过mmap函数我们将该物理内存地址映射到进程地址空间中最终实现操作共享内存的功能。实例功能服务端创建共享内存并将内存映射到进程地址空间中然后进行定时修改内存内容。客户端映射共享内存到进程地址空间中定时获取内存内容。实例代码服务端代码#include #include #include #include TEST(shm_test, server) { int fd shm_open(/shm01, O_CREAT | O_RDWR, 0777); // int fd open(/dev/shm/shm01, O_CREAT | O_RDWR); if (fd 0) { std::cout error to create or open std::endl; return; } std::cout create or open ok std::endl; ftruncate(fd, 4096);// 分配4KB内存 char *ptr (char *)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); char a[] 00; for (char k 0; k 26; k) { memset(a, a k, 1 *sizeof(char)); strcpy(ptr, a); sleep(1); } strcpy(ptr, a); mumap((void *)ptr, 4096); // 关闭映射 exit(0);}客户端代码#include #include #include #include TEST(test, client) { int fd shm_open(/shm01, O_RDWR, 0777); // int fd open(/dev/shm/shm01, O_CREAT | O_RDWR); if (fd 0) { std::cout error to open std::endl; return; } char *ptr (char *)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); while(true) { std::cout ptr std::endl; sleep(1); } exit(0);}执行结果开头的z是之前保存在共享内存中的数据可以看到客户端输出了英语字母。遇到的问题找不到shm_open的符号链接答在编译时链接rt库使用googletest时缺失pthread答链接pthread库总结本篇文章我们知道了共享内存通过共享内存和mmap我们能很轻易地完成进程间通讯(IPC Inter-Process Communication)进程间的semaphore(信号量)实现方式也是通过mmap和共享变量实现的。文章出处https://my.oschina.net/StupidZhe/blog/4647178