专业的赣州网站建设,网站设计包含哪些技术,主页网址,网站建设品牌推广seo内存映射#xff08;mmap#xff09;
概述
内存映射#xff08;mmap#xff09;是一种将文件或设备映射到进程地址空间的机制。通过内存映射#xff0c;进程可以像访问普通内存一样访问文件#xff0c;也可以用于进程间通信。mmap提供了高效的文件I/O和进程间通信方式。
…内存映射mmap概述内存映射mmap是一种将文件或设备映射到进程地址空间的机制。通过内存映射进程可以像访问普通内存一样访问文件也可以用于进程间通信。mmap提供了高效的文件I/O和进程间通信方式。通信原理基本概念内存映射的特点文件映射将文件映射到进程地址空间共享映射多个进程可以共享同一映射区域零拷贝直接内存访问减少数据拷贝虚拟内存利用虚拟内存机制按需加载同步机制可以自动同步到文件实现机制文件映射创建映射使用mmap()将文件映射到进程地址空间返回映射区域的虚拟地址可以指定映射大小、权限、标志等访问数据进程通过指针直接访问映射区域访问时触发页错误内核按需加载文件内容修改数据时根据标志决定是否写回文件同步msync()手动同步映射区域到文件munmap()取消映射自动同步数据流向进程A ──┐ ├── [共享映射区域] ── [文件/设备] 进程B ──┤ 进程C ──┘匿名映射进程间通信创建匿名映射使用mmap()创建匿名映射不关联文件使用MAP_SHARED标志多个进程可以共享通过fork()或显式共享实现进程间通信共享机制父子进程通过fork()共享映射区域任意进程可以通过文件描述符共享需要特殊处理API说明mmap()#includesys/mman.hvoid*mmap(void*addr,size_tlength,intprot,intflags,intfd,off_toffset);功能创建内存映射参数addr建议的映射地址通常为NULL让系统选择length映射长度字节prot保护标志PROT_READ可读PROT_WRITE可写PROT_EXEC可执行flags映射标志MAP_SHARED共享MAP_PRIVATE私有MAP_ANONYMOUS匿名等fd文件描述符匿名映射时为-1offset文件偏移量通常为0返回值成功返回映射地址失败返回MAP_FAILEDmunmap()intmunmap(void*addr,size_tlength);功能取消内存映射参数addr映射地址length映射长度返回值成功返回0失败返回-1msync()intmsync(void*addr,size_tlength,intflags);功能同步映射区域到文件参数addr映射地址length同步长度flags同步标志MS_SYNC同步写MS_ASYNC异步写MS_INVALIDATE使缓存无效返回值成功返回0失败返回-1示例代码示例: 使用 mmap 读写文件#includestdio.h#includesys/mman.h#includesys/stat.h#includefcntl.h#includeunistd.h#includestring.hintmain(){constchar*pathdemo.txt;constchar*msghello mmap\n;intfdopen(path,O_RDWR|O_CREAT,0666);if(fd0){perror(open);return1;}// 确保文件大小 要写入的长度size_tlenstrlen(msg);if(ftruncate(fd,len)-1){perror(ftruncate);close(fd);return1;}// 建立映射: 读写, 共享写回文件void*addrmmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(addrMAP_FAILED){perror(mmap);close(fd);return1;}// 写入数据memcpy(addr,msg,len);// 同步到文件if(msync(addr,len,MS_SYNC)-1){perror(msync);}// 读取验证write(STDOUT_FILENO,addr,len);// 清理munmap(addr,len);close(fd);return0;}示例: 多线程共享 mmap 区域并安全更新#includestdio.h#includestdlib.h#includepthread.h#includesys/mman.h#includesys/stat.h#includefcntl.h#includeunistd.h#includestring.h#defineTHREADS4#definePER_THREAD100000structshared{pthread_mutex_tlock;intcounter;};void*worker(void*arg){structshared*sh(structshared*)arg;for(inti0;iPER_THREAD;i){pthread_mutex_lock(sh-lock);sh-counter;pthread_mutex_unlock(sh-lock);}returnNULL;}intmain(){constchar*pathshared.dat;intfdopen(path,O_RDWR|O_CREAT,0666);if(fd0){perror(open);return1;}// 准备文件长度if(ftruncate(fd,sizeof(structshared))-1){perror(ftruncate);close(fd);return1;}// 建立映射structshared*shmmap(NULL,sizeof(structshared),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(shMAP_FAILED){perror(mmap);close(fd);return1;}// 初始化锁和计数器pthread_mutexattr_tattr;pthread_mutexattr_init(attr);pthread_mutexattr_setpshared(attr,PTHREAD_PROCESS_PRIVATE);// 同一进程线程间共享pthread_mutex_init(sh-lock,attr);sh-counter0;// 创建线程pthread_tth[THREADS];for(inti0;iTHREADS;i){pthread_create(th[i],NULL,worker,sh);}for(inti0;iTHREADS;i){pthread_join(th[i],NULL);}printf(Final counter %d (expect %d)\n,sh-counter,THREADS*PER_THREAD);// 清理pthread_mutex_destroy(sh-lock);munmap(sh,sizeof(structshared));close(fd);return0;}说明:使用 MAP_SHARED 将文件映射为共享区域通过 pthread_mutex_t 保证多线程更新的原子性如果要在多进程间共享, 将PTHREAD_PROCESS_PRIVATE改为PTHREAD_PROCESS_SHARED, 并确保映射为 MAP_SHARED 且 mutex 存放于共享内存中示例: 多进程(父子进程)共享 mmap 区域并安全更新#includestdio.h#includestdlib.h#includeunistd.h#includesys/mman.h#includesys/stat.h#includesys/wait.h#includefcntl.h#includepthread.h#includestring.h#includeerrno.h#definePROCESSES4#definePER_PROCESS100000// 共享数据结构, 包含互斥锁和计数器structshared{pthread_mutex_tlock;// 进程间共享的互斥锁intcounter;// 共享计数器intinitialized;// 初始化标志, 确保只初始化一次};intmain(){constchar*pathshared_mmap.dat;intfd;structshared*sh;pid_tpids[PROCESSES];inti;// 创建或打开共享文件fdopen(path,O_RDWR|O_CREAT,0666);if(fd0){perror(open);return1;}// 调整文件大小以容纳共享数据结构if(ftruncate(fd,sizeof(structshared))-1){perror(ftruncate);close(fd);return1;}// 建立共享内存映射// MAP_SHARED 确保多个进程共享同一块物理内存sh(structshared*)mmap(NULL,sizeof(structshared),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(shMAP_FAILED){perror(mmap);close(fd);return1;}// 父进程负责初始化共享数据结构if(sh-initialized0){// 初始化进程间共享的互斥锁属性pthread_mutexattr_tattr;pthread_mutexattr_init(attr);// 关键: 设置为进程间共享, 这样多个进程可以使用同一个互斥锁pthread_mutexattr_setpshared(attr,PTHREAD_PROCESS_SHARED);// 初始化互斥锁if(pthread_mutex_init(sh-lock,attr)!0){perror(pthread_mutex_init);munmap(sh,sizeof(structshared));close(fd);return1;}pthread_mutexattr_destroy(attr);// 初始化计数器sh-counter0;// 设置初始化标志, 防止子进程重复初始化sh-initialized1;printf(Parent: Initialized shared memory\n);}// 创建多个子进程for(i0;iPROCESSES;i){pids[i]fork();if(pids[i]0){perror(fork);// 清理已创建的子进程for(intj0;ji;j){kill(pids[j],SIGTERM);}munmap(sh,sizeof(structshared));close(fd);return1;}elseif(pids[i]0){// 子进程: 执行计数器递增操作printf(Child %d (PID %d): Starting increments\n,i,getpid());for(intj0;jPER_PROCESS;j){// 加锁保护临界区pthread_mutex_lock(sh-lock);sh-counter;pthread_mutex_unlock(sh-lock);}printf(Child %d (PID %d): Completed increments\n,i,getpid());// 子进程退出, munmap 会自动清理映射exit(0);}}// 父进程等待所有子进程完成printf(Parent: Waiting for all children to complete...\n);for(i0;iPROCESSES;i){intstatus;waitpid(pids[i],status,0);if(WIFEXITED(status)){printf(Parent: Child %d (PID %d) exited with status %d\n,i,pids[i],WEXITSTATUS(status));}}// 验证最终结果printf(Parent: Final counter %d (expected %d)\n,sh-counter,PROCESSES*PER_PROCESS);if(sh-counterPROCESSES*PER_PROCESS){printf(Parent: Success! Counter is correct.\n);}else{printf(Parent: Error! Counter mismatch (race condition detected).\n);}// 清理资源pthread_mutex_destroy(sh-lock);munmap(sh,sizeof(structshared));close(fd);// 可选: 删除共享文件// unlink(path);return0;}说明:使用MAP_SHARED标志创建共享内存映射, 多个进程可以访问同一块物理内存使用PTHREAD_PROCESS_SHARED属性的互斥锁, 确保多个进程可以正确同步父进程负责初始化共享数据结构(互斥锁和计数器)多个子进程并发更新共享计数器, 通过互斥锁保证原子性所有进程通过fork()共享父进程的映射区域, 无需额外文件操作示例: 多个独立进程通过文件共享 mmap 区域// writer.c: 写入进程#includestdio.h#includestdlib.h#includesys/mman.h#includesys/stat.h#includefcntl.h#includeunistd.h#includepthread.h#includestring.hstructshared{pthread_mutex_tlock;charmessage[256];intready;};intmain(){constchar*pathshared_mmap.dat;intfdopen(path,O_RDWR|O_CREAT,0666);if(fd0){perror(open);return1;}if(ftruncate(fd,sizeof(structshared))-1){perror(ftruncate);close(fd);return1;}structshared*sh(structshared*)mmap(NULL,sizeof(structshared),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(shMAP_FAILED){perror(mmap);close(fd);return1;}// 初始化互斥锁(仅第一次)if(sh-ready0){pthread_mutexattr_tattr;pthread_mutexattr_init(attr);pthread_mutexattr_setpshared(attr,PTHREAD_PROCESS_SHARED);pthread_mutex_init(sh-lock,attr);pthread_mutexattr_destroy(attr);sh-ready1;}// 写入数据pthread_mutex_lock(sh-lock);snprintf(sh-message,sizeof(sh-message),Hello from writer (PID %d),getpid());printf(Writer: Wrote message\n);pthread_mutex_unlock(sh-lock);sleep(2);// 等待读取进程读取munmap(sh,sizeof(structshared));close(fd);return0;}// reader.c: 读取进程#includestdio.h#includestdlib.h#includesys/mman.h#includesys/stat.h#includefcntl.h#includeunistd.h#includepthread.hstructshared{pthread_mutex_tlock;charmessage[256];intready;};intmain(){constchar*pathshared_mmap.dat;intfdopen(path,O_RDWR,0666);if(fd0){perror(open);return1;}structshared*sh(structshared*)mmap(NULL,sizeof(structshared),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(shMAP_FAILED){perror(mmap);close(fd);return1;}// 等待写入进程初始化while(sh-ready0){usleep(100000);// 100ms}// 读取数据pthread_mutex_lock(sh-lock);printf(Reader: Read message: %s\n,sh-message);pthread_mutex_unlock(sh-lock);munmap(sh,sizeof(structshared));close(fd);return0;}说明:两个独立的程序通过同一个文件共享 mmap 映射区域写入进程负责初始化互斥锁和数据结构读取进程等待初始化完成后读取数据两个进程可以独立编译和运行, 通过文件系统协调性能评价优点高效零拷贝直接内存访问虚拟内存利用虚拟内存机制按需加载大文件处理适合处理大文件无需一次性加载进程间通信可以用于进程间共享数据灵活性可以映射文件或创建匿名映射缺点需要同步多进程访问需要同步机制复杂性API相对复杂需要理解虚拟内存系统限制受虚拟内存大小限制文件依赖文件映射依赖文件系统性能特点延迟低直接内存访问吞吐量高零拷贝适合大文件CPU占用低利用虚拟内存机制内存占用按需加载节省内存适用场景✅ 大文件处理✅ 需要高效文件I/O的场景✅ 进程间共享数据✅ 需要零拷贝的场景✅ 数据库、缓存等应用❌ 小文件简单读写普通I/O更简单❌ 不需要共享的场景注意事项同步机制多进程访问共享映射时需要同步机制如信号量页大小对齐注意系统页大小某些操作需要页对齐文件大小映射大小不能超过文件大小除非扩展文件权限设置注意prot和flags的权限设置错误处理注意处理MAP_FAILED返回值资源清理使用完毕后调用munmap()取消映射同步时机根据需要使用msync()同步数据到文件匿名映射匿名映射用于进程间通信时需要特殊机制共享扩展阅读man 2 mmapman 2 munmapman 2 msyncman 7 shm_overview