您的位置:首页 > 文旅 > 美景 > 百度获客平台怎么收费的_产品设计专业就业前景如何_企业网站建设的重要性_谷歌seo 优化

百度获客平台怎么收费的_产品设计专业就业前景如何_企业网站建设的重要性_谷歌seo 优化

2024/12/21 22:04:10 来源:https://blog.csdn.net/m0_74795952/article/details/144571466  浏览:    关键词:百度获客平台怎么收费的_产品设计专业就业前景如何_企业网站建设的重要性_谷歌seo 优化
百度获客平台怎么收费的_产品设计专业就业前景如何_企业网站建设的重要性_谷歌seo 优化

5.共享映射区(无血缘关系用的)

文章目录

    • 5.共享映射区(无血缘关系用的)
      • 1.概述
      • 2.mmap&&munmap函数
      • 3.mmap注意事项
      • 4.mmap实现进程通信
        • 父子进程
          • 练习
        • 无血缘关系
      • 5.mmap匿名映射区

1.概述

  • 原理:共享映射区是将文件内容映射到进程的地址空间中,使得多个进程可以通过访问这个共享的内存区域来实现通信。进程对映射区域的操作就如同对文件进行操作一样,这些操作会直接反映在文件和其他共享该映射区域的进程中。

  • 示例场景:多个进程需要共同操作一个配置文件,通过将该配置文件映射到共享映射区,进程可以直接在内存中读取和修改配置信息,而不需要频繁地进行文件 I/O 操作。

  • 优点:结合了内存操作的高效性和文件存储的持久性;可以方便地在不相关的进程之间实现通信,只要它们能访问到同一个文件。

  • 缺点:对文件的操作需要注意同步问题,否则可能导致数据不一致;文件大小可能会限制共享映射区的大小。

**存储映射I/O(Memory-mapped l/O)使一个磁盘文件与内存存储空间中的一个缓冲区相映射。**于是当从缓冲区中取数据,就相当于读文件中的相应字节。于此类似,将数据存入缓冲区,则相应的字节就自动写入文件。这样,就可在不适用read和write函数的情况下,使用地址(指针)完成I/O操作。

使用这种方法,首先应通知内核,将一个指定文件映射到存储区域中。这个映射工作可以通过mmap函数来实
现。

2.mmap&&munmap函数

创建共享内存映射

include<sys/mman.h>
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----就是把-1强转为void *了

释放共享内存映射

int munmap(void *addr, size_t length);

参数

addr:mmap 的返回值,共享内存映射首地址

length:大小

返回值

成功0,失败-1

函数使用

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{char *p = NULL;int fd;fd = open("testmap", O_RDWR|O_CREAT|O_TRUNC, 0644);     // 创建文件用于创建映射区if (fd == -1)sys_err("open error");
/*lseek(fd, 10, SEEK_END);            // 两个函数等价于 ftruncate()函数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");            // 写操作printf("----%s\n", p);              // 读操作int ret = munmap(p, len);           // 释放映射区if (ret == -1) {sys_err("munmap error");}return 0;
}

3.mmap注意事项

思考 :

  1. 可以open的时候O_CREAT一个新文件来创建映射区吗 ?

  2. 如果open时O_RDONLY,mmap时PROT参数指定PROT_READ|PROT_WRITE会怎样 ?

  3. 文件描述符先关闭,对mmap映射有没有影响 ?

  4. 如果文件偏移量为1000会怎样 ?

  5. 对mem越界操作会怎样?

  6. 如果mem++,munmap可否成功 ?

  7. mmap什么情况下会调用失败 ?

    很多参数都会导致失败

  8. 如果不检测mmap的返回值,会怎样?

    会死得很惨

使用注意事项:

  1. 用于创建映射区的文件大小为 0,却指定非0大小创建映射区,出 “总线错误”。
  2. 用于创建映射区的文件大小为 0,也指定0大小创建映射区, 出 “无效参数”。
  3. 用于创建映射区的文件读写属性为,只读,映射区属性为 读、写。 出 “无效参数”; 文件和映射区都是只读的是可以的;文件只有写权限,映射区只有写权限也会报错。(2答案)
  4. 创建映射区,需要read权限。当访问权限指定为 “共享”MAP_SHARED是, mmap的读写权限应该 <=文件的open权限。 映射区只写不行。
  5. 文件描述符fd,在mmap创建映射区完成即可关闭。后续访问文件,用 地址访问。(3答案)
  6. offset 必须是 4096的整数倍。(MMU 映射的最小单位 4k )(4答案)
  7. 对申请的映射区内存,不能越界访问。 (5答案)
  8. 读写都没问题,但是munmap会失败,munmap用于释放的 地址,必须是mmap申请返回的地址。(6答案)
  9. 映射区访问权限为 “私有”MAP_PRIVATE, 对内存所做的所有修改,只在内存有效,不会反应到物理磁盘上。
  10. 映射区访问权限为 “私有”MAP_PRIVATE, 只需要open文件时,文件有读权限,用于创建映射区即可。

image-20241218222315367

mmap函数的保险调用方式:

1. fd = open("文件名", O_RDWR);
2. mmap(NULL, 有效文件大小, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

4.mmap实现进程通信

父子进程

父子等有血缘关系的进程之间也可以通过mmap建立的映射区来完成数据通信。

但相应的要在创建映射区的时候指定对应的标志位参数flags:

MAP_PRIVATE:(私有映射)父子进程各自独占映射区;

MAP_SHARED:(共享映射) 父子进程共享映射区;

结论:

父子进程共享:1. 打开的文件 2.mmap建立的映射区(但必须要使用MAP_SHARED)

流程:

父子进程使用 mmap 进程间通信:

1.父进程 先 创建映射区。 open( O_RDWR) mmap( MAP_SHARED );

2.指定 MAP_SHARED 权限

3.fork() 创建子进程。

4.一个进程读, 另外一个进程写。

练习

练习:父进程创建映射区,然后fork子进程,子进程修改映射区内容,而后,父进程读取映射区内容,查验是
否共享

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>int var = 100;int main(void)
{int *p;pid_t pid;int fd = open("temp", O_RDWR);//p = (int *)mmap(NULL, 40, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);p = (int *)mmap(NULL, 490, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);//p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 私有的不行if(p == MAP_FAILED){		//注意:不是p == NULLperror("mmap error");exit(1);}close(fd);pid = fork();				//创建子进程if(pid == 0){*p = 7000;               // 写共享内存var = 1000;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;
}
无血缘关系

流程: 【要求会写】

1.两个进程 打开同一个文件,创建映射区。

2.指定flags 为 MAP_SHARED。

3.一个进程写入,另外一个进程读出。

【注意】:无血缘关系进程间通信。

​ mmap:数据可以重复读取。

​ fifo:数据只能一次读取。

读端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>struct 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);usleep(10000);}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.h>struct 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;
}

5.mmap匿名映射区

匿名映射:只能用于 血缘关系(父子)进程间通信。

p = (int *)mmap(NULL, 40, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);

映射区大小想要多少写多少

权限想要啥写啥

文件描述符的地方传-1

flags要 | 下面提到的两个宏

image-20241218224059685

/dev/zero 从这个文件里面拿数据可以随便拿,想要多大拿多大的数据,只不过读出来都是文件空洞

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com