Linux系统编程 --- 共享内存及内存映射【十全十美】

简介:

 一.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. #include <unistd.h> 
  2. #include <sys/types.h> 
  3. #include <sys/stat.h> 
  4. #include <fcntl.h> 
  5.  
  6. #include <signal.h> 
  7.  
  8.  
  9. #include <sys/mman.h> /* for mmap,shm_open */ 
  10. #include <string.h> 
  11.  
  12. #include <stdio.h> 
  13. #include <stdlib.h> 
  14. #include <errno.h> 
  15.  
  16.  
  17. #define PRINT_INTX(e) printf("%s=0x%X\n",#e,e) 
  18.  
  19.  
  20. typedef struct mmap_fd{ 
  21.    int fd; /* 打开后的文件描述符*/ 
  22.    void * base; /* 在进程内部的地址*/ 
  23.    char * name; /* 共享内存名字 */ 
  24.     int len ; /* 共享内存长度 */ 
  25.     int offset; /* fd中的偏移量*/ 
  26. }MMAP_FD; 
  27.  
  28.  
  29. #define MMAP_ADDR(p) (p)->base 
  30.  
  31.  
  32. MMAP_FD * shm_map(char * name,int len,int offset) 
  33.    MMAP_FD * p_fd; 
  34.    void * base; 
  35.  
  36.    int fd; 
  37.      
  38.   //第一步:创建一个共享内存 
  39.  
  40.     fd = shm_open(name,O_CREAT|O_EXCL|O_RDWR,666); 
  41.      if(fd == -1) 
  42.       { 
  43.          if(errno == EEXIST) 
  44.             { 
  45.               fd = shm_open(name,O_RDWR,666); 
  46.              } 
  47.       } 
  48.  
  49.    
  50.    if(fd == -1) 
  51.        { 
  52.          perror("shm_open"); 
  53.        return NULL; 
  54.        } 
  55.  
  56.     //第二步:设置内存大小 
  57.  
  58.       if(ftruncate(fd,len) == -1) 
  59.           { 
  60.                  perror("ftruncate"); 
  61.                shm_unlink(name); 
  62.                return NULL; 
  63.           } 
  64.  
  65.     //第三步,将内核中共享内存映射到进程空间之上 
  66.  
  67.   //void *mmap(void *start, size_t length, int prot, int flags, 
  68.  
  69. // int fd, off_t offset); 
  70.  
  71.       base = mmap(NULL,len,PROT_READ | PROT_WRITE, MAP_SHARED ,fd,offset); 
  72.        if(base == MAP_FAILED) 
  73.         { 
  74.              perror("mmap"); 
  75.              shm_unlink(name); 
  76.               return NULL; 
  77.          } 
  78.         
  79.  
  80.         p_fd = malloc(sizeof(MMAP_FD)); 
  81.          p_fd->len = len; 
  82.          p_fd->name = strdup(name); 
  83.          p_fd->fd = fd; 
  84.          p_fd->base = base; 
  85.          p_fd->offset = offset; 
  86.  
  87.     return p_fd; 
  88.      
  89.  
  90.  
  91. int shm_destroy(MMAP_FD * p_fd) 
  92.    if(p_fd == NULL) 
  93.       return -1; 
  94.    //取消映射 
  95.  
  96.    if(munmap(p_fd->base,p_fd->len) == -1) 
  97.       { 
  98.           perror("munmap"); 
  99.            return -1; 
  100.       } 
  101.  
  102.    //删除共享内存 
  103.  
  104.     if(shm_unlink(p_fd->name) == -1) 
  105.       { 
  106.            perror("shm_unlink"); 
  107.              return -2; 
  108.       } 
  109.  
  110.    free(p_fd->name); 
  111.    free(p_fd); 
  112.  
  113.     return 0; 
  114.  
  115.  
  116. #define SHM_NAME "test_mmap" 
  117.  
  118.  MMAP_FD * p_fd = NULL; 
  119.  
  120. void exit_handler(int sig) 
  121.    printf("EXIT HANDLER\n"); 
  122.    shm_destroy(p_fd); 
  123.    exit(0); 
  124.  
  125. //创建进程,用于写数据 
  126.  
  127. void write_proc() 
  128.   
  129.   char ary[10]; 
  130.    char * p ; 
  131.    static int count = 1; 
  132.  
  133.       printf("WRITE SHM\n"); 
  134.  
  135.    signal(SIGINT,exit_handler); 
  136.    signal(SIGTERM,exit_handler); 
  137.      
  138.  
  139.    p_fd = shm_map(SHM_NAME,100,0); 
  140.    if(p_fd == NULL) 
  141.          return ; 
  142.  
  143.     p= malloc(10); 
  144. //注意各种变量地址,ary空间是栈,p是堆的,p_fd->base是内存映射地址 
  145.    PRINT_INTX(ary); 
  146.    PRINT_INTX(MMAP_ADDR(p_fd)); 
  147.  
  148.    PRINT_INTX(p); 
  149.  
  150.    free(p); 
  151.  
  152.  
  153.    while(1) 
  154.     { 
  155.       snprintf(MMAP_ADDR(p_fd),p_fd->len,"mmap write %d\n",count++); 
  156.       sleep(1); 
  157.     } 
  158.  
  159.    
  160.  
  161.  
  162. void read_proc() 
  163.    signal(SIGINT,exit_handler); 
  164.    signal(SIGTERM,exit_handler); 
  165.  
  166.    printf("READ SHM\n"); 
  167.  
  168.    p_fd = shm_map(SHM_NAME,100,0); 
  169.    if(p_fd == NULL) 
  170.          return ; 
  171.  
  172.    while(1) 
  173.     { 
  174.       printf(MMAP_ADDR(p_fd)); 
  175.       sleep(1); 
  176.     } 
  177.  
  178. int main(int argc,char * argv[]) 
  179.    if((argc>1) && (argv[1][0] == 'r')) 
  180.        read_proc(); 
  181.    else 
  182.        write_proc(); 



本文转自 驿落黄昏 51CTO博客,原文链接:http://blog.51cto.com/yiluohuanghun/1081585 ,如需转载请自行联系原作者

相关文章
|
22天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
61 3
|
22天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
57 2
|
20天前
|
缓存 Java Linux
如何解决 Linux 系统中内存使用量耗尽的问题?
如何解决 Linux 系统中内存使用量耗尽的问题?
103 48
|
20天前
|
监控 Java Android开发
深入探讨Android系统的内存管理机制
本文将深入分析Android系统的内存管理机制,包括其内存分配、回收策略以及常见的内存泄漏问题。通过对这些方面的详细讨论,读者可以更好地理解Android系统如何高效地管理内存资源,从而提高应用程序的性能和稳定性。
51 16
|
16天前
|
Ubuntu Linux 网络安全
linux系统ubuntu中在命令行中打开图形界面的文件夹
在Ubuntu系统中,通过命令行打开图形界面的文件夹是一个高效且实用的操作。无论是使用Nautilus、Dolphin还是Thunar,都可以根据具体桌面环境选择合适的文件管理器。通过上述命令和方法,可以简化日常工作,提高效率。同时,解决权限问题和图形界面问题也能确保操作的顺利进行。掌握这些技巧,可以使Linux操作更加便捷和灵活。
15 3
|
20天前
|
缓存 Linux
如何检查 Linux 内存使用量是否耗尽?
何检查 Linux 内存使用量是否耗尽?
|
22天前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
59 3
|
25天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
41 6
|
25天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
61 6
|
26天前
|
机器学习/深度学习 自然语言处理 Linux
Linux 中的机器学习:Whisper——自动语音识别系统
本文介绍了先进的自动语音识别系统 Whisper 在 Linux 环境中的应用。Whisper 基于深度学习和神经网络技术,支持多语言识别,具有高准确性和实时处理能力。文章详细讲解了在 Linux 中安装、配置和使用 Whisper 的步骤,以及其在语音助手、语音识别软件等领域的应用场景。
54 5