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



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

相关文章
|
Ubuntu Linux Anolis
Linux系统禁用swap
本文介绍了在新版本Linux系统(如Ubuntu 20.04+、CentOS Stream、openEuler等)中禁用swap的两种方法。传统通过注释/etc/fstab中swap行的方式已失效,现需使用systemd管理swap.target服务或在/etc/fstab中添加noauto参数实现禁用。方法1通过屏蔽swap.target适用于新版系统,方法2通过修改fstab挂载选项更通用,兼容所有系统。
1102 3
Linux系统禁用swap
|
Linux
Linux系统修改网卡名为eth0、eth1
在Linux系统中,可通过修改GRUB配置和创建Udev规则或使用systemd链接文件,将网卡名改为`eth0`、`eth1`等传统命名方式,适用于多种发行版并支持多网卡配置。
1672 3
|
Ubuntu Linux 网络安全
Linux系统初始化脚本
一款支持Rocky、CentOS、Ubuntu、Debian、openEuler等主流Linux发行版的系统初始化Shell脚本,涵盖网络配置、主机名设置、镜像源更换、安全加固等多项功能,适配单/双网卡环境,支持UEFI引导,提供多版本下载与持续更新。
1176 3
Linux系统初始化脚本
|
缓存 监控 Linux
Linux内存问题排查命令详解
Linux服务器卡顿?可能是内存问题。掌握free、vmstat、sar三大命令,快速排查内存使用情况。free查看实时内存,vmstat诊断系统整体性能瓶颈,sar实现长期监控,三者结合,高效定位并解决内存问题。
1152 0
Linux内存问题排查命令详解
|
安全 Linux Shell
Linux系统提权方式全面总结:从基础到高级攻防技术
本文全面总结Linux系统提权技术,涵盖权限体系、配置错误、漏洞利用、密码攻击等方法,帮助安全研究人员掌握攻防技术,提升系统防护能力。
1284 1
|
Linux
Linux 更改共享内存tmpfs的大小
通过挂载的方式在原有目录或新建目录改造 如: [root@luozhonghua /]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/vg_luozhonghua-lv_root 21G 4.
1637 0
|
Linux 应用服务中间件 Shell
二、Linux文本处理与文件操作核心命令
熟悉了Linux的基本“行走”后,就该拿起真正的“工具”干活了。用grep这个“放大镜”在文件里搜索内容,用find这个“探测器”在系统中寻找文件,再用tar把东西打包带走。最关键的是要学会使用管道符|,它像一条流水线,能把这些命令串联起来,让简单工具组合出强大的功能,比如 ps -ef | grep 'nginx' 就能快速找出nginx进程。
1137 1
二、Linux文本处理与文件操作核心命令
linux命令—stat
`stat` 是 Linux 系统中用于查看文件或文件系统详细状态信息的命令。相比 `ls -l`,它提供更全面的信息,包括文件大小、权限、所有者、时间戳(最后访问、修改、状态变更时间)、inode 号、设备信息等。其常用选项包括 `-f` 查看文件系统状态、`-t` 以简洁格式输出、`-L` 跟踪符号链接,以及 `-c` 或 `--format` 自定义输出格式。通过这些选项,用户可以灵活获取所需信息,适用于系统调试、权限检查、磁盘管理等场景。
848 137
|
安全 Ubuntu Unix
一、初识 Linux 与基本命令
玩转Linux命令行,就像探索一座新城市。首先要熟悉它的“地图”,也就是/根目录下/etc(放配置)、/home(住家)这些核心区域。然后掌握几个“生存口令”:用ls看周围,cd去别处,mkdir建新房,cp/mv搬东西,再用cat或tail看文件内容。最后,别忘了随时按Tab键,它能帮你自动补全命令和路径,是提高效率的第一神器。
1818 58
|
存储 安全 Linux
Linux卡在emergency mode怎么办?xfs_repair 命令轻松解决
Linux虚拟机遇紧急模式?别慌!多因磁盘挂载失败。本文教你通过日志定位问题,用`xfs_repair`等工具修复文件系统,三步快速恢复。掌握查日志、修磁盘、验重启,轻松应对紧急模式,保障系统稳定运行。
1745 2