建设网站对公司起什么作用,网站进行诊断,wordpress可注册,新乡网站建设找哪家前言#xff1a;
mmap是一种内存映射文件的方法#xff0c;即将一个文件或者其它对象映射到进程的地址空间#xff0c;实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后#xff0c;进程就可以采用指针的方式读写操作这一段内存
mmap是一种内存映射文件的方法即将一个文件或者其它对象映射到进程的地址空间实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后进程就可以采用指针的方式读写操作这一段内存而系统会自动回写脏页面到对应的文件磁盘上即完成了对文件的操作而不必再调用read,write等系统调用函数。相反内核空间对这段区域的修改也直接反映用户空间从而可以实现不同进程间的文件共享。
目录 一.文件间进程通信 二、存储映射I/O
三、mmap函数
1.创建共享内存映射
2.释放映射区
*3.使用注意事项
*4.mmap函数的保险调用方式
5.mmap父子进程通信
6.无血缘关系进程间 mmap 通信 一.文件间进程通信
打开的文件是内核中的一块缓冲区。多个无血缘关系的进程可以同时访问该文件。
两个完全独立没有血缘关系的进程文件之间也可以完成进程间的通信 test1.c 先执行,将数据写入文件test.txt /** 先执行,将数据写入文件test.txt*/
#include stdio.h
#include unistd.h
#include fcntl.h
#include stdlib.h
#include string.h#define N 5int main(void)
{char buf[1024];char *str --------------secesuss-------------\n;int ret;int fd open(test.txt, O_RDWR|O_TRUNC|O_CREAT, 0664);//直接打开文件写入数据write(fd, str, strlen(str));printf(test1 write into test.txt finish\n);sleep(N);lseek(fd, 0, SEEK_SET);ret read(fd, buf, sizeof(buf));ret write(STDOUT_FILENO, buf, ret);if (ret -1) {perror(write second error);exit(1);}close(fd);return 0;
}test2.c 后执行,尝试读取另外一个进程写入文件的内容
/** 后执行,尝试读取另外一个进程写入文件的内容*/
#include stdio.h
#include unistd.h
#include stdlib.h
#include fcntl.h
#include string.hint main(void)
{char buf[1024];char *str ----------test2 write secesuss--------\n;int ret;sleep(2); //睡眠2秒,保证test1将数据写入test.txt文件int fd open(test.txt, O_RDWR);//尝试读取test.txt文件中test1写入的数据ret read(fd, buf, sizeof(buf)); //将读到的数据打印至屏幕write(STDOUT_FILENO, buf, ret);//写入数据到文件test.txt中, 未修改读写位置write(fd, str, strlen(str));printf(test2 read/write finish\n);close(fd);return 0;
}二、存储映射I/O 存储映射I/o(Memory-mapped l/o)使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当从缓冲区中取数据就相当于读文件中的相应字节。于此类似将数据存入缓冲区则相应的字节就自动写入文件。这样就可在不适用read和write函数的情况下使用地址指针完成l/o操作。 使用这种方法首先应通知内核将一个指定文件映射到存储区域中。这个映射工作可以通过 mmap函数来实现。 三、mmap函数 1.创建共享内存映射
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
参数 addr 指定映射区的首地址。通常传NULL表示让系统自动分配 length 共享内存映射区的大小。 文件的实际大小 prot 共享内存映射区的读写属性。 PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE flags 标注共享内存的共享属性。 MAP_SHARED、MAP_PRIVATE fd: 用于创建共享内存映射区的那个文件的文件描述符。 offset 默认0表示映射文件全部。偏移位置。需是 4k 的整数倍。
返回值 成功映射区的首地址。 失败MAP_FAILED (void*(-1)) errno 2.释放映射区
int munmap(void *addr, size_t length); addrmmap 的返回值 length大小
#include stdio.h
#include stdlib.h
#include string.h
#include errno.h
#include pthread.h
#include sys/mman.h
#include fcntl.hvoid sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc,char *argv[])
{char *p NULL;int fd;//打开或者创建tetsmap文件fd open(testmap,O_RDWR|O_CREAT|O_TRUNC,0644);if(fd -1){sys_err(open error);}/*两个函数等价于ftruncate()函数lseek(fd,10,SEEK_END);write(fd,\0,1);*/ftruncate(fd,20);int len lseek(fd,0,SEEK_END);p mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(p MAP_FAILED){sys_err(mmap error);}//使用p对文件进行读写操作strcpy(p,hello mmap\n);printf(-------%s\n,p);//写操作int ret munmap(p,len);if(ret -1){sys_err(munmap error);}return 0;
}*3.使用注意事项
语法
open()方法语法格式如下os.open(file, flags[, mode]);参数
file – 要打开的文件flags – 该参数可以是以下选项多个使用 “|” 隔开O_RDONLY: 以只读的方式打开
O_WRONLY: 以只写的方式打开
O_RDWR : 以读写的方式打开
O_NONBLOCK: 打开时不阻塞
O_APPEND: 以追加的方式打开
O_CREAT: 创建并打开一个新文件
O_TRUNC: 打开一个文件并截断它的长度为零必须有写权限
O_EXCL: 如果指定的文件存在返回错误
O_SHLOCK: 自动获取共享锁
O_EXLOCK: 自动获取独立锁
O_DIRECT: 消除或减少缓存效果
O_FSYNC : 同步写入
O_NOFOLLOW: 不追踪软链接1PROT_READ表示内存段内的内容可写2PROT_WRITE表示内存段内的内容可读3PROT_EXEC表示内存段中的内容可执行4PROT_NONE表示内存段中的内容根本没法访问。 1. 用于创建映射区的文件大小为 0实际指定非0大小创建映射区出 “总线错误”。 fd open(testmap,O_RDWR|O_CREAT|O_TRUNC,0644); //O_RDWR : 以读写的方式打开if(fd -1){sys_err(open error);}//ftruncate(fd,20);//int len lseek(fd,0,SEEK_END);int len 20;//PROT_READ表示内存段内的内容可写 PROT_WRITE表示内存段内的内容可读p mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); //可读可写2 用于创建映射区的文件大小为 0实际制定0大小创建映射区 出 “无效参数”。 fd open(testmap,O_RDWR|O_CREAT|O_TRUNC,0644); //O_RDWR : 以读写的方式打开if(fd -1){sys_err(open error);}//ftruncate(fd,20);//int len lseek(fd,0,SEEK_END);int len 0;//PROT_READ表示内存段内的内容可写 PROT_WRITE表示内存段内的内容可读p mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); //可读可写3. 用于创建映射区的文件读写属性为只读。映射区属性为 读、写。 出 “无效参数”。 fd open(testmap,O_RDONLY|O_CREAT|O_TRUNC,0644); //O_RDONLY: 以只读的方式打开if(fd -1){sys_err(open error);}ftruncate(fd,20);int len lseek(fd,0,SEEK_END);//int len 0;//PROT_READ表示内存段内的内容可写 PROT_WRITE表示内存段内的内容可读p mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); //可读可写 4. 创建映射区需要read权限。当访问权限指定为 “共享”MAP_SHARED是 mmap的读写权限应该 文件的open权限。 只写不行。 //fd open(testmap,O_RDONLY|O_CREAT|O_TRUNC,0644);fd open(testmap,O_WRONLY); //文件的只写if(fd -1){sys_err(open error);}ftruncate(fd,20);int len lseek(fd,0,SEEK_END);//int len 0;p mmap(NULL,len,PROT_WRITE,MAP_SHARED,fd,0); //文件只写fd open(testmap,O_RDWR); //文件的读写注意当文件是读写的时候可以写当文件是只读的时候可以是只读。当文件是只写的时候不能写 5. 文件描述符fd在mmap创建映射区完成即可关闭。后续访问文件用地址访问。 //fd open(testmap,O_RDONLY|O_CREAT|O_TRUNC,0644);fd open(testmap,O_RDWR);if(fd -1){sys_err(open error);}ftruncate(fd,20);int len lseek(fd,0,SEEK_END);//int len 0;p mmap(NULL,len,PROT_WRITE,MAP_SHARED,fd,0);//文件只写if(p MAP_FAILED){sys_err(mmap error);}close(fd); //创建映射区完成即可关闭6. offset 必须是 4096的整数倍。MMU 映射的最小单位 4k
p mmap(NULL,len,PROT_WRITE,MAP_SHARED,fd,1000); p mmap(NULL,len,PROT_WRITE,MAP_SHARED,fd,4096); 7. 对申请的映射区内存不能越界访问。
p mmap(NULL,len,PROT_WRITE,MAP_SHARED,fd,0);.......strcpy(plen4096*4,hello mmap\n);8. munmap用于释放的地址必须是mmap申请返回的地址。
p mmap(NULL,len,PROT_WRITE,MAP_SHARED,fd,0);.......strcpy(p,hello mmap\n); 解决方法 char *temp p;strcpy(temp,hello mmap\n);9. 映射区访问权限为 “私有”MAP_PRIVATE, 对内存所做的所有修改只在内存有效不会反应到物理磁盘上。 int fdfd open(testmap,O_RDWR|O_CREAT|O_TRUNC,0644);//fd open(testmap,O_RDWR);if(fd -1){sys_err(open error);}ftruncate(fd,20);int len lseek(fd,0,SEEK_END);//int len 0;p mmap(NULL,len,PROT_WRITE|PROT_READ,MAP_PRIVATE,fd,0);//可读可写 10.映射区访问权限为 “私有”MAP_PRIVATE, 需要open文件时有读权限用于创建映射区即可。 int fd;//int fd open(testmap,O_RDWR|O_CREAT|O_TRUNC,0644);fd open(testmap,O_RDONLY); //O_RDONLY: 以只读的方式打开if(fd -1){sys_err(open error);}//ftruncate(fd,20);int len lseek(fd,0,SEEK_END);//int len 0;p mmap(NULL,len,PROT_WRITE|PROT_READ,MAP_PRIVATE,fd,0);//可读可写if(p MAP_FAILED){sys_err(mmap error);}*4.mmap函数的保险调用方式 1. fd open文件名 O_RDWR; 2. mmap(NULL, 有效文件大小 PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
5.mmap父子进程通信 父子等有血缘关系的进程之间也可以通过 mmap建立的映射区来完成数据通信。但相应的要在创建映射区的时候指定对应的标志位参数flags: MAP_PRIVATE:(私有映射)父子进程各自独占映射区; MAP_SHARED:(共享映射)父子进程共享映射区;
父进程创建映射区然后fork子进程子进程修改映射区内容而后父进程读取映射区内容查验是否共享。
思路
父进程先创建映射区。 open O_RDWR mmap( MAP_SHARED ); 指定 MAP_SHARED 权限 fork() 创建子进程。 一个进程读 另外一个进程写。
#include stdio.h
#include stdlib.h
#include string.h
#include fcntl.h
#include sys/mman.h
#include sys/wait.h
#include unistd.h//全局变量
int var 100;int main(void)
{int *p;pid_t pid;int fd;fd open(temp,O_RDWR|O_CREAT|O_TRUNC,0644);if(fd 0){perror(open error);exit(1);}unlink(temp);ftruncate(fd,4);p (int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); //MAP_SHARED共享映射//p (int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0); //MAP_PRIVATE私有映射if(p MAP_FAILED){ //注意不是p NULLperror(mapp error);exit(1);}close(fd); //映射区建立完毕即可关闭文件pid fork(); //创建子进程if(pid 0){ //子进程*p 2000; //写共享内存var 1000;printf(child *p %d,var %d\n,*p,var);}else if(pid 0){ //父进程sleep(1);printf(parent *p %d,var %d\n,*p,var); //读共享内存wait(NULL);int ret munmap(p,4); //释放映射区if(ret -1){perror(munmap error);exit(1);}}return 0;
}//p (int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); //MAP_SHARED共享映射p (int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0); //MAP_PRIVATE私有映射 6.无血缘关系进程间 mmap 通信 两个进程 打开同一个文件创建映射区。 指定flags 为 MAP_SHARED。 一个进程写入另外一个进程读出。 【注意】无血缘关系进程间通信。 mmap数据可以重复读取。 fifo数据只能一次读取。
匿名映射只能用于血缘关系进程间通信
p (int *)mmap(NULL, 40,PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
写端
#include stdio.h
#include stdlib.h
#include string.h
#include fcntl.h
#include sys/mman.h
#include unistd.h
#include errno.hstruct student {int id;char name[256];int age;
};void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{struct student stu {1, xiaoming, 18};struct student *p;int fd; fd open(test_map, O_RDWR|O_CREAT|O_TRUNC, 0664);
// fd open(test_map, O_RDWR);if (fd -1)sys_err(open error);ftruncate(fd, sizeof(stu));p mmap(NULL, sizeof(stu), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (p MAP_FAILED)sys_err(mmap error);close(fd);while (1) {memcpy(p, stu, sizeof(stu));stu.id;sleep(2);}munmap(p, sizeof(stu));return 0;
}读端
#include stdio.h
#include stdlib.h
#include string.h
#include fcntl.h
#include sys/mman.h
#include unistd.h
#include errno.hstruct student {int id;char name[256];int age;
};void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{struct student stu;struct student *p;int fd; fd open(test_map, O_RDONLY);if (fd -1)sys_err(open error);p mmap(NULL, sizeof(stu), PROT_READ, MAP_SHARED, fd, 0);if (p MAP_FAILED)sys_err(mmap error);close(fd);while (1) {printf(id %d, name%s, age%d\n, p-id, p-name, p-age);sleep(1);}munmap(p, sizeof(stu));return 0;
}