zoukankan      html  css  js  c++  java
  • 共享内存解读

    环境: linux (ubuntu server 64)

    1. Posix共享内存
      1. 来源:最初用读写同一个文件的方式实现管道、消息队列的机制,后来加以改进,将文件映射到内存来实现,完成高效的通信机制(这里的文件和共享内存区是“同步的”,即一致的,同时也不会是时时刻刻的一致,内核会完成这里的刷新工作。只是对于原来的读写文件,这里变成了读写内存。而这些通信由内核控制完成)。
      2.  进阶:使用最初的方式来打开共享内存,但是并不真的需要真的生成一个真实的文件,直接操作内存。同时内核会完成保存和更新与这块共享内存相关的伪文件信息(不包括文件里的内容)
    2. System V共享内存

         直接类似于Posix的进阶版本

      3. Bus Error(总线错误)

        1. 内存字节对齐(本人也是初次听说,不太支持这个观点)

          如int类型的未4字节,参见http://blog.sina.com.cn/s/blog_54f82cc201010zzh.html

          本人反驳,是因为:

          

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 
      5 int main()
      6 {
      7     char s[100] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
      8             0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00 };
      9     char *str = s+10;
     10     int *pint;
     11     for(int i=0;i<4;i++)
     12     {
     13         pint = (int *) (str+i);
     14         printf("%X
    ",*pint);
     15     }
     16     return 0;
     17 }
     18                                                                                 
    View Code

          运行结果:

          

        2. 进程控制块(PCB)未知的内存访问错误

          共享内存等,并不在PCB中有参考的内存访问。于是访问一块共享内存时,进程本身不能对访问的地址进行检查,越界时便触发Bus Error(总线错误)。

        3.   其他。//了解得不多了

      4. Posix内存映射文件的问题

        甚至在一些书上都写着使用内存去映射一个文件时,可以不用去理会文件本身的大小,可以访问超越文件大小的地方。

        这样的说法是不全对的。(这一点也确实害了我不浅)

        因为使用内存映射就要向操作系统申请内存时,操作系统都是一个Page的大小为单位进行分配的。当文件大小不为整数个Page大小时,便会多得到一些映射的内存(即文件大小按Page单位取上整)。 

        于是内存映射文件就存在这样一个问题:像通过这样的方式,去申请一块大于被映射文件一个Page大小的内存是不成功的(不一定立即返回错误),但是实际申请到的内存是限制大小的。

        这时访问的内存就可能不成功!参见下面代码

    1 #include <unistd.h> 
      2 #include <cstdio> 
      3 #include <cstring> 
      4 #include <cstdlib> 
      5 #include <sys/types.h> 
      6 #include <sys/stat.h> 
      7 #include <fcntl.h> 
      8 #include <sys/mman.h> 
      9  
     10 #define handle_error(msg)  
     11         do { perror(msg); exit(EXIT_FAILURE); } while (0) 
     12 int main() 
     13 { 
     14     int fd = open("testfile",O_RDWR | O_CREAT, 0666); 
     15     if(fd == -1) 
     16         handle_error("testfile open error
    "); 
     17  
     18     //lseek(fd, 30, SEEK_SET); 
     19     ftruncate(fd, 10); 
     20     char *addr = (char *) mmap(NULL, 4096 + 30, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 
     21     if(addr == MAP_FAILED) 
     22         handle_error("mmap failed"); 
     23     setbuf(stdout, NULL); 
     24     const char *ss = "ss, Hello World
    "; 
     25     //write(fd,(void *)ss, strlen(ss));  
     26     printf("%s",addr); 
     27     addr[0] = 'l'; 
     28     sprintf(addr, "source, Hello World
    "); 
     29     close(fd);  //fd close之后访问addr的合法区任然成功,文件和内存的同步仍然有效
     30     addr[0] = 'k';   
     31     printf("%s",addr); 
     32  
     33     sprintf(addr+4095, "Dangerous Trial");  //注销这两行,程序便执行成功
     34     printf("%s
    ", addr+4095); 
     35     return 0; 
     36 } 
     37  
     38 //g++ main.cpp -lrt     
    View Code

          总结: 使用Posix共享内存时第一步应该使用ftruncate将被映射的伪文件扩展到一定的大小!

           

  • 相关阅读:
    centos 6 关闭防火墙
    linux 卸载openJDK
    elasticsearch-head 配置
    elasticsearch6.5.x-centos6
    gitbook 安装和使用
    ubuntu 开启关闭mysql服务
    spring boot 项目使用idea正常打包后执行总是出现异常,解决办法
    idea导入配置SSM项目,并进行打包
    正则表达式规则
    Debug --> 对于pcap包中的某一packet的小分析
  • 原文地址:https://www.cnblogs.com/karlvin/p/3598227.html
Copyright © 2011-2022 走看看