• 【Linux】:共享内存


    一.原理

    直接原理

    共享内存顾名思义就是共同使用的一块空间。

    在这里插入图片描述

    很明显操作系统需要对这块内存进行管理,那么就避免不了先描述后组织的策略。

    二.创建共享内存

    1.shmget

    申请一块共享内存-shmget

    在这里插入图片描述

    第二个参数:创建共享内存的大小,单位字节。

    第三个参数:多个选项
    在这里插入图片描述

    返回值:如果成功返回共享内存标识符,如果失败返回-1。

    操作系统怎么保证不同进程看到同一个共享内存呢?怎么知道这块内存是否存在呢? 这就需要对第一个参数进行讨论了。

    在这里插入图片描述

    2.写一个共享内存代码

    comm.hpp

    #ifndef __COMM_HPP__
    #define __COMM_HPP__
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int size=4096;
    const string path="/home/chz";//任意写
    const int proj_id=0x6666;//任意写
    
    key_t Getkey()//获取一个key
    {
      key_t k=ftok(path.c_str(),proj_id);
      if(k<0)
      {
        perror("Create key wrong\n");
        exit(1);
      }
      cout<<"Create key sucess,key:"<<k<<endl;
      return k;
    }
    
    int GetshareMem()//获取一个chmid
    {
      key_t k=Getkey();
      int shmid=shmget(k,size,IPC_CREAT|IPC_EXCL|0666);//创建方式和权限
      if(shmid<0)
      {
        perror("Create shmget wrong\n");
        exit(2);
      }
      cout<<"Create shmget sucess,shmid;"<<shmid<<endl;
      return shmid;
    }
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    前面说过共享内存如果不主动释放会一直存在,所以在调用该函数后我们可以使用ipcs -m查看内核的进程资源。

    在这里插入图片描述

    perms是权限,nattch是与之相连的文件,byte是共享内存大小(建议一般按4096的整数倍创建,因为系统一次分配的最小内存是4KB)。

    使用ipcrm -m+shmid可以手动删除。

    在这里插入图片描述

    三.进行通信

    1.各种接口

    将共享内存挂入

    在这里插入图片描述

    第一个参数毫无疑问是共享内存标识符。

    第二个参数一般设置为NULL。因为共享内存是在物理内存上,要将其挂到虚拟内存的共享区,但具体挂到共享区哪个位置一般由操作系统决定。该函数的返回值就是具体的起始地址。

    第三个参数一般设为0。它是改变挂接时的权限,虽然我们设置的共享内存权限是666,但可以通过这个参数让它只读。

    取消挂入

    在这里插入图片描述

    控制共享内存

    在这里插入图片描述

    第二个参数:要进行什么操作。(有许多参数可以自行查看,这里使用 IPC_RMID删除该共享内存)

    第三个参数:共享内存的属性。

    2.各接口使用代码

    processa.cc

    #include"comm.hpp"
    #include 
    
    
    int main()
    {
      int shmid=GetshareMem();
    
      sleep(3);
      char*shmaddr=(char*)shmat(shmid,NULL,0);//将共享内存挂入
      cout<<"挂入内存"<<endl;
    
      sleep(3);
      shdit(shmaddr);//取消挂入
      cout<<"取消挂入"<<endl;
    
      sleep(3);
      shmctl(shmid,IPC_RMID,nullptr);//销毁共享内存
      cout<<"销毁共享内存"<<endl;
    
    
    
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述

    3.一次简单的通信

    稍微修改一下comm.hpp,主要在shmget,当一个进程创建时,让另一个进程能获取

    #ifndef __COMM_HPP__
    #define __COMM_HPP__
    #include 
    #include 
    #include 
    #include 
    
    
    using namespace std;
    
    const int size=4096;
    const string path="/home/chz";//任意写
    const int proj_id=0x6666;//任意写
    
    key_t Getkey()//获取一个key
    {
      key_t k=ftok(path.c_str(),proj_id);
      if(k<0)
      {
        perror("Create key wrong\n");
        exit(1);
      }
      cout<<"Create key sucess,key:"<<k<<endl;
      return k;
    }
    
    int GetShareMemHelper(int flag)//获取一个chmid
    {
      key_t k=Getkey();
      int shmid=shmget(k,size,flag);//创建方式和权限
      if(shmid<0)
      {
        perror("Create shmget wrong\n");
        exit(2);
      }
      cout<<"Create shmget sucess,shmid;"<<shmid<<endl;
      return shmid;
    }
    
    int CreateShm()
    {
      return GetShareMemHelper(IPC_CREAT|IPC_EXCL|0666);
    }
    
    int GetShm()
    {
      return GetShareMemHelper(IPC_CREAT);
    }
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    processa.cc

    #include"comm.hpp"
    #include 
    
    
    int main()
    {
      int shmid=CreateShm();//创建共享内存
      //挂入内存
      //获取起始地址,并把它当作字符串使用
      char*shmaddr=(char*)shmat(shmid,nullptr,0);
      while(true)
      {
        //直接读取
        cout<<"I am read:";
        cout<<shmaddr<<endl;
        sleep(1);
      }
      shmdt(shmaddr);//取消挂起
      shmctl(shmid,IPC_RMID,nullptr);
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    processb.cc

    #include"comm.hpp"
    
    int main()
    {
      int shmid=GetShm();//获取共享内存
      //挂入内存
      //获取起始地址,并把它当作字符串使用
      char*shmaddr=(char*)shmat(shmid,nullptr,0);
    
      while(true)
      {
        cout<<"please Enter:";
        fgets(shmaddr,4096,stdin);//直接从键盘读入
      }
    
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    makefile

    .PHONY:all
    all:processa processb
    
    processa:processa.cc
    	g++ -o $@ $^ -std=c++11
    processb:processb.cc
    	g++ -o $@ $^ -std=c++11
    
    .PHONY:clean
    clean:
    	rm -f processa processb
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    四.共享内存的特点

    1.共享内存没有同步互斥之类的保护机制。(即使没有写入也依然会读)
    2.共享内存是所有的进程通信中最快的。(拷贝少)
    3.共享内存里的所有数据由用户自己维护。(操作系统不会自动将数据清零)

  • 相关阅读:
    Spring漏洞综合利用
    #经典论文 异质山坡的物理模型 2 有效导水率
    敏捷开发、V模型开发、瀑布模型
    【Helm三部曲】 Helm 简介及安装
    C#开发的OpenRA游戏之金钱系统(1)
    H5前端开发——DOM
    【Java刷题进阶】基础入门篇
    计算机竞赛 机器视觉opencv答题卡识别系统
    计算机毕业设计之java+javaweb的影院管理系统-电影院管理系统
    P1008 [NOIP1998 普及组] 三连击
  • 原文地址:https://blog.csdn.net/m0_73790767/article/details/134519215