织梦CMS - 轻松建站从此开始!

罗索

Linux系统编程 --- 共享内存及内存映射

jackyhwei 发布于 2010-12-01 15:49 点击:次 
共享内存是在进程间共享某一块内存。是最快一种ipc通信机构。其中posix共享内存机制 它主要是通过内存映射(mmap)机制来实现的。
TAG:

Andrew Huang bluedrum@163.com 转载请注明作者及联络方式
一.POSIX共享内存的实现
-----------------------------------------------------------------------------
共享内存是在进程间共享某一块内存。是最快一种ipc通信机构。其中posix共享内存机制 它主要是通过内存映射(mmap)机制来实现的。
在进程间共享内存使用如下固定步骤:
    1.创建一个共享内存
        int shm_open(const char *name, int oflag, mode_t mode);
            name是共享内存名字,各个进程通过名字来找到同一块内存.
            oflag,是这个内存属性。类似于文件属性。使用O_RDWR/O_RDONLY/O_CREAT,第一次创建共享内存必须带O_CREAT标志位。
            mode,是权限代码。
         当其打开成功是会在建立一个虚拟的文件 /dev/shm/shm.XXXX,其中XXXX是name的名字
         例: int fd = shm_open("test",O_RDWR,666);
          将会创建 /dev/shm/shm.test文件。
         shm_open成功后,将返回一个文件描述符fd.你可以理解是在内核的中分配一段空间,并分配一个fd号给应用程序使用。
        这里要注意,如果一个进程已经创建一个共享内存,后面其它的进程打开这个共享内存只需要用
      shm_open(name,flag,0);
2.设置内存大小。
         int ftruncate(int fd, off_t length);
      ftruncate操作的fd即可是一个文件open后的fd,也可是shm_open打开的fd  .
         普通文件将会被ftruncate强行设为length大小(不够加0空间,超过则被截断
       如果共享内存,将表示把共享内存设为length大小.
       如果设置 ftruncate返回0
3.用mmap 眏射到进程空间当中某一个地址上
       void *mmap(void *start, size_t length, int prot, int flags,int fd, off_t offset);
           start是表示开始映射的物理地址,如果为NULL表示由内核自行选择合适空间来分配。
          length是内存的大小,一般是和第二步的同一大小。
          prot 是共享内存属性。它有如下值
                 PROT_EXEC 分配空间可执行
                 PROT_READ 分配空间可读
                 PROT_WRITE 可写
                 PROT_NONE 禁止访问,一般为省事,都设为  PROT_READ|PROT_WRITE
          flags 是共享内存的标志位,它有如下取值
                 MAP_FIXED ,内存固定大小,不能超过一页。如果超过将mmap失败.
                  MAP_SHARED ,在多个进程间共享这一内存
                  MAP_PRIVATE, 只供本进程使用。
          fd 是shm_open或open创建文件的描述符.
          offset 是在共享内存或文件中的偏移量。一般是0
        如果映射成功,将会返回一个进程内部地址。对这个地址访问即是对内核共享内存的访问。这个地址位于堆和栈的空闲区。
        如果失败,将返回MAP_FAILED (它等于 (void *)-1)
   到mmap后,对共享内存的操作就跟与普通内存没有什么区别了。如使用memcpy/memset等操作.
   如果结束的对共享内存使用,即可采用接下两步.
 4.munmap解除当前进程对这块共享映射。
   int munmap(void *start, size_t length);
   start是映射的进程内地址,lenght是内存的长度
   如果映射是文件,它还有存盘功能。
 5.从内核清除共享内存
    int shm_unlink(const char *name);
    name是共享内存名字,如果有多个进程打开这个内存,只有最后使用进程调用shm_unlink,这个共享内存才会真正清除掉。
                
 二.POSIX共享内存实现代码
---------------------------------------------------------------------------
  1. /* 
  2.  Author: Andrew Huang <bluedru@163.com> 
  3. */ 
  4. #include <unistd.h> 
  5. #include <sys/types.h> 
  6. #include <sys/stat.h> 
  7. #include <fcntl.h> 
  8. #include <signal.h> 
  9. #include <sys/mman.h> /* for mmap,shm_open */ 
  10. #include <string.h> 
  11. #include <stdio.h> 
  12. #include <stdlib.h> 
  13. #include <errno.h> 
  14.  
  15. #define PRINT_INTX(e) printf("%s=0x%X\n",#e,e) 
  16.  
  17. typedef struct mmap_fd{ 
  18.    int fd; /* 打开后的文件描述符*/ 
  19.    void * base; /* 在进程内部的地址*/ 
  20.    char * name; /* 共享内存名字 */ 
  21.    int len ; /* 共享内存长度 */ 
  22.    int offset; /* fd中的偏移量*/ 
  23. }MMAP_FD; 
  24.  
  25. #define MMAP_ADDR(p) (p)->base 
  26.  
  27. MMAP_FD * shm_map(char * name,int len,int offset) 
  28.    MMAP_FD * p_fd; 
  29.    void * base; 
  30.    int fd; 
  31.   //第一步:创建一个共享内存 
  32.    fd = shm_open(name,O_CREAT|O_EXCL|O_RDWR,666); 
  33.    if(fd == -1) 
  34.    { 
  35.       if(errno == EEXIST 
  36.       { 
  37.          fd = shm_open(name,O_RDWR,666); 
  38.       } 
  39.    } 
  40.    if(fd == -1) 
  41.    { 
  42.      perror("shm_open"); 
  43.      return NULL; 
  44.    } 
  45.  
  46.     //第二步:设置内存大小 
  47.     if(ftruncate(fd,len) == -1) 
  48.     { 
  49.       perror("ftruncate"); 
  50.       shm_unlink(name); 
  51.       return NULL; 
  52.     } 
  53.     //第三步,将内核中共享内存映射到进程空间之上 
  54. //void *mmap(void *start, size_t length, int prot, int flags, 
  55. // int fd, off_t offset); 
  56.     base = mmap(NULL,len,PROT_READ | PROT_WRITE, MAP_SHARED ,fd,offset); 
  57.     if(base == MAP_FAILED) 
  58.     { 
  59.       perror("mmap"); 
  60.       shm_unlink(name); 
  61.       return NULL; 
  62.      } 
  63.      p_fd = malloc(sizeof(MMAP_FD)); 
  64.      p_fd->len = len; 
  65.      p_fd->name = strdup(name); 
  66.      p_fd->fd = fd; 
  67.      p_fd->base = base; 
  68.      p_fd->offset = offset; 
  69.   return p_fd; 
  70.  
  71. int shm_destroy(MMAP_FD * p_fd) 
  72.    if(p_fd == NULL) 
  73.       return -1; 
  74.    //取消映射 
  75.    if(munmap(p_fd->base,p_fd->len) == -1) 
  76.    { 
  77.      perror("munmap"); 
  78.      return -1; 
  79.    } 
  80.  
  81.    //删除共享内存 
  82.    if(shm_unlink(p_fd->name) == -1) 
  83.    { 
  84.      perror("shm_unlink"); 
  85.      return -2; 
  86.    } 
  87.  
  88.    free(p_fd->name); 
  89.    free(p_fd); 
  90.    return 0; 
  91.  
  92. #define SHM_NAME "test_mmap" 
  93.  
  94. MMAP_FD * p_fd = NULL; 
  95.  
  96. void exit_handler(int sig) 
  97.    printf("EXIT HANDLER\n"); 
  98.    shm_destroy(p_fd); 
  99.    exit(0); 
  100.  
  101. //创建进程,用于写数据 
  102. void write_proc() 
  103.    char ary[10]; 
  104.    char * p ; 
  105.    static int count = 1; 
  106.  
  107.    printf("WRITE SHM\n"); 
  108.  
  109.    signal(SIGINT,exit_handler); 
  110.    signal(SIGTERM,exit_handler); 
  111.  
  112.    p_fd = shm_map(SHM_NAME,100,0); 
  113.    if(p_fd == NULL) 
  114.          return ; 
  115.  
  116.     p= malloc(10); 
  117.  
  118.  
  119. //注意各种变量地址,ary空间是栈,p是堆的,p_fd->base是内存映射地址 
  120.    PRINT_INTX(ary); 
  121.    PRINT_INTX(MMAP_ADDR(p_fd)); 
  122.  
  123.    PRINT_INTX(p); 
  124.  
  125.    free(p); 
  126.  
  127.    while(1) 
  128.     { 
  129.       snprintf(MMAP_ADDR(p_fd),p_fd->len,"mmap write %d\n",count++); 
  130.       sleep(1); 
  131.     } 
  132.  
  133. void read_proc() 
  134.    signal(SIGINT,exit_handler); 
  135.    signal(SIGTERM,exit_handler); 
  136.  
  137.    printf("READ SHM\n"); 
  138.  
  139.    p_fd = shm_map(SHM_NAME,100,0); 
  140.    if(p_fd == NULL) 
  141.          return ; 
  142.  
  143.    while(1) 
  144.     { 
  145.       printf(MMAP_ADDR(p_fd)); 
  146.       sleep(1); 
  147.     } 
  148.  
  149. int main(int argc,char * argv[]) 
  150.    if((argc>1) && (argv[1][0] == 'r')) 
  151.        read_proc(); 
  152.    else 
  153.        write_proc(); 

 

(Andrew Huang)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201012/10552.html]
本文出处:bluedrum.cublog.cn  作者:Andrew Huang
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容