廊坊做网站厂商定制,高端网站建站 北京,深圳龙岗房价2023最新价格,时尚女装网站设计共享存储映射
文件进程间通信
使用文件也可以完成 IPC#xff0c;理论依据是#xff0c;fork 后#xff0c;父子进程共享文件描述符。也就共享打开的文件。 编程#xff1a;父子进程共享打开的文件。借助文件进行进程间通信。 测试代码
/*** 父子进程共享打开的文件描述…共享存储映射
文件进程间通信
使用文件也可以完成 IPC理论依据是fork 后父子进程共享文件描述符。也就共享打开的文件。 编程父子进程共享打开的文件。借助文件进行进程间通信。 测试代码
/*** 父子进程共享打开的文件描述符----使用文件完成进程间通信**/#includestdio.h
#includeunistd.h
#includestring.h
#includestdlib.h
#includefcntl.h
#includesys/wait.hint main(void)
{int fd1,fd2;pid_t pid;char buf[1024]; char *str----------test for shared fd in parent child process -----\n;pidfork();if(pid0){perror(fork error);exit(1);}else if(pid0){fd1open(test.txt,O_RDWR);if(fd10){perror(open error);exit(1);} write(fd1,str,strlen(str));printf(child wrote over...\n);}else{fd2open(test.txt,O_RDWR);if(fd20){perror(open error);exit(1);}sleep(1); //保证子进程写入数据int len read(fd2,buf,sizeof(buf));write(STDOUT_FILENO,buf,len);wait(NULL);//回收防止僵尸进程}return 0;
}思考无血缘关系的进程可以打开同一个文件进行通信吗为什么 可以无血缘关系的进程也可以打开同一个文件进行通信方法一样因为这些进程打开的是同一个进程。其实在打开文件时调用open时操作系统内核就调用了mmap。因为一个文件只有一个文件结构体FILE打开时位于内核被打开这个文件的多个进程共享。
存储映射 I/O
存储映射 I/O(Memory-mappedI/O) 使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当从缓冲区中取 数据就相当于读文件中的相应字节。于此类似将数据存入缓冲区则相应的字节就自动写入文件。这样就可 在不适用 read 和 write 函数的情况下使用地址指针完成 I/O 操作。 使用这种方法首先应通知内核将一个指定文件映射到存储区域中。这个映射工作可以通过 mmap 函数来实 现。
mmap 函数
void* mmap(void* adrr,size_t length,int prot,int flags,int fd,off_toffset); 返回成功返回创建的映射区首地址失败MAP_FAILED 宏 参数 addr: 建立映射区的首地址由 Linux 内核指定。使用时直接传递 NULL length 欲创建映射区的大小 prot 映射区权限 PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE flags 标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区) MAP_SHARED: 会将映射区所做的操作反映到物理设备磁盘上。 MAP_PRIVATE: 映射区所做的修改不会反映到物理设备。 fd 用来建立映射区的文件描述符 offset 映射文件的偏移(4k 的整数倍) #includestdio.h#includefcntl.h#includeunistd.h#includestring.h#includestdlib.h#includesys/mman.hint main(void){int len,ret;char *pNULL;int fd open(mytest.txt,O_CREAT|O_RDWR,0644);if(fd0){perror(open error);exit(1);} //确定文件大小len ftruncate(fd,4);if(len -1){perror(ftruncate error:);exit(1);} p mmap(NULL, 4 , PROT_READ|PROT_WRITE , MAP_SHARED, fd, 0); if(p MAP_FAILED){perror(mmap error:);exit(1);} strcpy(p,abc);//写数据ret munmap(p,4);//释放映射区 if(ret-1){perror(munmap error:);exit(1);} close(fd);return 0;}munmap 函数
同 malloc 函数申请内存空间类似的mmap 建立的映射区在使用结束后也应调用类似 free 的函数来释放。 int munmap(void *addr,size_t length); 成功0 失败-1
mmap 注意事项
思考
可以 open 的时候 O_CREAT 一个新文件来创建映射区吗? 答可以但新CREATE出来的文件不行必须要有实际的大小如果 open 时 O_RDONLY,mmap 时 PROT 参数指定 PROT_READ|PROT_WRITE 会怎样 答不行创建映射区的权限小于等于打开文件的权限映射区创建的过程中存在一次读文件操作权限不足。文件描述符先关闭对 mmap 映射有没有影响 答 没有影响文件描述符是操作文件的句柄有映射区了就是地址的方式操作所以文件描述符就没意义了。如果文件偏移量为 1000 会怎样 答不行偏移量必须是一页的大小4k对 mem 越界操作会怎样 答不行释放映射区可能会失败只有创建映射区的地址和释放时的地址要是同一个地址如果 memmunmap 可否成功 答不能释放映射区的时候要传首地址和映射区大小给munmap但后首地址就不是创建时的首地址只有创建映射区的地址和释放时的地址要是同一个地址mmap 什么情况下会调用失败 8. 如果不检测 mmap 的返回值会怎样 答返回值必须检查空间不能为0文件大小和映射区要匹配等等情况下会失败
总结
创建映射区的过程中隐含着一次对映射文件的读操作。当 MAP_SHARED 时要求映射区的权限应 文件打开的权限(出于对映射区的保护)。而 MAP_PRIVATE 则无所谓因为 mmap 中的权限是对内存的限制。映射区的释放与文件关闭无关。只要映射建立成功文件可以立即关闭。特别注意当映射文件大小为 0 时不能创建映射区。所以用于映射的文件必须要有实际大小 mmap 使用时常常会出现总线错误通常是由于共享文件存储空间大小引起的。munmap 传入的地址一定是 mmap 的返回地址。坚决杜绝指针操作。如果文件偏移量必须为 4K 的整数倍 7. mmap 创建映射区出错概率非常高一定要检查返回值确保映射区建立成功再进行后续操作。
mmap 父子进程通信
父子等有血缘关系的进程之间也可以通过 mmap 建立的映射区来完成数据通信。但相应的要在创建映射区的时 候指定对应的标志位参数 flags
MAP_PRIVATE: (私有映射) 父子进程各自独占映射区MAP_SHARED: (共享映射) 父子进程共享映射区 编程父进程创建映射区然后 fork 子进程子进程修改映射区内容而后父进程读取映射区内容查验是 否共享 #includestdio.h #includestdlib.h#includeunistd.h#includefcntl.h#includesys/mman.h#includesys/wait.hint var100;int main(void ){int *p;pid_t pid;int fd;fdopen(temp,O_RDWR|O_CREAT|O_TRUNC,0644);if(fd0){perror(open error:);exit(1);}unlink(temp); //删除临时文件目录项使之具备被释放条件,所有使用该文件的进程结束后该文件才释放ftruncate(fd,4); //创建文件大小p(int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//父子进程共享映射区// p(int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);//对映射区各自独占 if(pMAP_FAILED){ //不是pNULL时出错perror(mmap,error); exit(1);}close(fd); //映射区建立完毕即可关闭文件//完成数据传递pidfork();if(pid0){*p2000;var1000;printf(child,*p%d,var %d\n,*p,var);}else{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;} 结论父子进程共享
打开的文件mmap 建立的映射区(但必须要使用 MAP_SHARED)
匿名映射
通过使用我们发现使用映射区来完成文件读写操作十分方便父子进程间通信也较容易。但缺陷是每次创 建映射区一定要依赖一个文件才能实现。通常为了建立映射区要 open 一个 temp 文件创建好了再 unlink、close 掉比较麻烦。 可以直接使用匿名映射来代替。其实 Linux 系统给我们提供了创建匿名映射区的方法无需依赖一 个文件即可创建映射区。同样需要借助标志位参数 flags 来指定。 使用 MAP_ANONYMOUS(或 MAP_ANON)
int*pmmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); 4随意举例该位置表大小可依实际需要填写。
需注意的是MAP_ANONYMOUS 和 MAP_ANON 这两个宏是 Linux 操作系统特有的宏。在类 Unix 系统中如无该 宏定义可使用如下两步来完成匿名映射区的建立。
fdopen(/dev/zero,O_RDWR);pmmap(NULL,size,PROT_READ|PROT_WRITE,MMAP_SHARED,fd,0);
示例代码
#includestdio.h
#includestdlib.h
#includeunistd.h
#includefcntl.h
#includesys/mman.h
#includesys/wait.hint var100;int main(void )
{int *p; pid_t pid;//不使用文件参数传-1 p(int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);//对映射区各自独占if(pMAP_FAILED){ //不是pNULL时出错perror(mmap,error); exit(1);} //完成数据传递pidfork();if(pid0){*p2000;var1000;printf(child,*p%d,var %d\n,*p,var);}else{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;
}Linux下这两个文件无大小 第一个文件好比聚宝盆可以随意映射 第二个文件一般错误洗脑洗重定向到这个文件中
mmap 无血缘关系进程间通信
实质上 mmap 是内核借助文件帮我们创建了一个映射区多个进程之间利用该映射区完成数据传递。由于内核 空间多进程共享因此无血缘关系的进程间也可以使用 mmap 来完成通信。只要设置相应的标志位参数 flags 即可。 若想实现共享当然应该使用 MAP_SHARED 了。 读数据
/** 非血缘关系进程间通信*/
#includestdio.h
#includesys/stat.h
#includefcntl.h
#includeunistd.h
#includestdlib.h
#includesys/mman.h
#includestring.hstruct STU{int id; char name[20];char sex;
};//出错处理函数
void sys_err(char *str)
{perror(str);exit(-1);
}int main(int argc,char *argv[])
{int fd; struct STU student;struct STU *mm;if(argc2){printf(./a.out file_shared\n);exit(-1);} fdopen(argv[1],O_RDONLY);if(fd -1) sys_err(open error);mm mmap(NULL,sizeof(student),PROT_READ,MAP_SHARED,fd,0);if(mm MAP_FAILED)sys_err(mmap error);close(fd);while(1){ //读进程 printf(id%d\tname%s\t%c\n,mm-id,mm-name,mm-sex);sleep(2);}munmap(mm,sizeof(student));return 0;
} 写数据
/* * 非血缘关系之间的通信*/
#includestdio.h
#includesys/stat.h
#includesys/types.h
#includefcntl.h
#includeunistd.h
#includestdlib.h
#includesys/mman.h
#includestring.hstruct STU{int id;char name[20];char sex;
};void sys_err(char *str)
{perror(str);exit(1);
}int main(int argc,char *argv[])
{int fd;struct STU student{10,xiaoming,m};char *mm;if(argc2){printf(./a.out file_shared\n);exit(-1);}fd open(argv[1],O_RDWR | O_CREAT,0644);ftruncate(fd,sizeof(student));mm mmap(NULL,sizeof(student),PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);if(mm MAP_FAILED)sys_err(mmap); close(fd);while(1){memcpy(mm,student,sizeof(student));student.id; //循环向内存复制sleep(1);}munmap(mm,sizeof(student));return 0;
}