共享内存解读

环境: 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\n",*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\n"); 
 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\n"; 
 25     //write(fd,(void *)ss, strlen(ss));  
 26     printf("%s",addr); 
 27     addr[0] = 'l'; 
 28     sprintf(addr, "source, Hello World\n"); 
 29     close(fd);  //fd close之后访问addr的合法区任然成功,文件和内存的同步仍然有效
 30     addr[0] = 'k';   
 31     printf("%s",addr); 
 32  
 33     sprintf(addr+4095, "Dangerous Trial");  //注销这两行,程序便执行成功
 34     printf("%s\n", addr+4095); 
 35     return 0; 
 36 } 
 37  
 38 //g++ main.cpp -lrt     
View Code

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

 

       

posted on 2014-03-13 11:59  男神发量  阅读(1003)  评论(0编辑  收藏  举报