• 23共享内存


    共享内存

    是最快的IPC通信方式,不存在数据复制,而是直接内存读写

    涉及到多个进程访问,可能出现同时读、写操作,一般采用信号量的方式,进行互斥操作

    步骤:

    内存共享使用

    1:  ftok         使用某个文件做关键字创建key

    2:  shmget    使用key 创建(打开)共享内存 shmid

    3:  shmat      打开(映射)共享内存. (attach)

    4:  memcpy   使用(读写)共享内存

    5:  shmdt       释放共享内存. (detach)

    6:  shmctl       删除共享内存

    创建共享内存

    <sys/ipc.h>

    <sys/shm.h>

    int  shmget(key_t key, size_t sz,  int shmflg)

    参数:

    key         ftok结果或者 IPC_PRIVATE

    sz           共享内存的大小

    shmflg    IPC_CREAT | IPC_EXCL | 访问权限

                  SHM_HUGETLB   内存分配 HUGETLB ‘巨页’内存

    shmat 

    void  *shmat(int shmid, void* shmaddr, int shmflg)

    将共享内存连接到指定的进程地址空间,使用共享内存

    参数:

    shmid         共享内存id

    shmaddr     连接的内存地址

                      NULL:  系统自动选择合适的内存地址(推荐)

                      非NULL: shmflg 指定 SHM_RND,

                                    把地址减去部分取SHMLBA整数倍

                                     shmaddr – (shmaddr % SHMLBA)

    shmflg      SHM_RND

                    SHM_RDONLY      只读访问

    注意:函数出错返回 -1, 不是NULL !!!!!!!!         

    shmdt

    int  shmdt(void *shmaddr)

    分离连接到进程地址空间的共享内存, 释放共享内存

    共享内存设置

    <sys/shm.h>

    int  shmctl(int shmid,  int cmd,  struct shmid_ds *buf);

    参数:

    shmid      共享内存ID

    cmd         要做的操作

    *buf        操作对应的数据

    cmd 参数

    IPC_STAT     将内核共享内存的相关数据读取到 buf中

    IPC_SET       将buf中的数据设置到共享内存

    IPC_RMID     删除共享内存

    (以下需要定义宏 _GNU_SOURCE)

    IPC_INFO     获取共享内存的系统限制,存入buf中

                          buf 指向 shminfo 结构体

    SHM_INFO   获取共享内存消耗的系统资源消息,存入buf中

                          buf 指向 shm_info 结构体(和IPC_INFO 不同)

    SHM_STAT   获取共享内存相关数据,同 IPC_STAT

                          shmid 使用内核中维护该共享内存数组的索引值

    SHM_LOCK    锁定共享内存,不允许进行交换到虚拟内存

    SHM_UNLOCK    解锁共享内存

    共享内存数据结构

    struct shmid_ds {

        struct ipc_perm shm_perm;  

        size_t                 shm_segsz;  //共享内存大小

        time_t                 shm_atime;  //最后调用shmat时间

        time_t                 shm_dtime;  //最后调用shmdt时间

        time_t                 shm_ctime;  //最后改变共享内存的时间

        pid_t                   shm_cpid;    //创建共享内存的进程

        pid_t                    shm_lpid;    //最后一次访问共享内存的进程

        shmatt_t              shm_nattch;  //当前连接的进程数

    }

    共享内存中的数据

    struct ipc_perm{

        key_t  key;               //msgget 的key参数

        uid_t   uid                //消息队列所有者 euid

        gid_t   gid;              //消息队列所有者 egid

        uid_t   cuid;             //消息队列创建者 euid

        gid_t   cgid;             //消息队列创建者 egid

        unsigned short mode;  //访问权限

        unsigned short  __seq;     //序列号

    }

    系统共享内存数据

    struct shminfo {

        unsigned long  shmmax;   //共享内存允许最大段数

        unsigned long  shmmin;    //共享内存最小段数

        unsigned long  shmmni;    //共享内存段最大个数

        unsigned long  shmseg;   //进程可以访问的最大段数(未使用)

        unsigned long  shmall;     //系统最大共享内存页

    }

    系统共享内存数据

    struct shm_info {

        int                 used_ids;          //当前系统中存在的共享内存

        unsigned long shm_tot;         //共享内存总页数

        unsigned long shm_rss;         //驻留的共享内存页数

        unsigned long shm_swp;        //交换的共享内存页数

        unsigned long swap_attempts;     //废弃

        unsigned long swap_successed;  //废弃

    }

    例子:

    #include<stdio.h>

    #include<string.h>

    #include<stdlib.h>

    #include<sys/ipc.h>

    #include<sys/shm.h>

    #define SHM_SIZE 0x100000

    typedef struct tagInfo

    {

          char szName[16];

          int  age;

          char szTel[16];

    }INFO_S;

    //写操作

    void writeMemory(int shmid)

    {

          //根据shmid连接共享内存,获取首地址

    INFO_S *pstAddr;

          pstAddr=(INFO_S*)shmat(shmid,NULL,0);

         

          INFO_S stInfo;

          int pos;

          while(1)

          {

               //共享内存指定位置写入内容

               fprintf(stderr,"input write pos:");

               scanf("%d",&pos);

              

    memset(&stInfo,0,sizeof(stInfo));

               fprintf(stderr,"input your infomation.. ");

               printf("name:");

               scanf("%s",stInfo.szName);

               printf("age:");

               scanf("%d",&(stInfo.age));

               printf("szTel:");

               scanf("%s",stInfo.szTel);

              

    //将内容放入内存

               memcpy(pstAddr+pos,&stInfo,sizeof(stInfo));

          }   

          shmdt(pstAddr);

          return ;

    }

    void readMemory(int shmid)

    {

          //根据shmid连接共享内存,获取首地址

          INFO_S *pstAddr;

          pstAddr=(INFO_S*)shmat(shmid,NULL,0);

         

          INFO_S stInfo;

          int pos;

          while(1)

          {

               //读取指定位置内容

               fprintf(stderr,"input read pos:");

               scanf("%d",&pos);

               memset(&stInfo,0,sizeof(stInfo));

               //读取

               memcpy(&stInfo,pstAddr+pos,sizeof(stInfo));

              

    printf("name:%s ",stInfo.szName);

               printf("age:%d ",stInfo.age);

               printf("szTel:%s ",stInfo.szTel);

          }   

          shmdt(pstAddr);

          return  ;

    }

    // shmid_ds属性

    void printShmInfo(struct shmid_ds* pstShm)

    {

          printf("----------------- SHMID_DS  ----------------- ");

          printf("Key        : %#x ", pstShm->shm_perm.__key);

          printf("Ownner uid : %d ",  pstShm->shm_perm.uid);

          printf("Ownner gid : %d ",  pstShm->shm_perm.gid);

          printf("Creater uid: %d ",  pstShm->shm_perm.cuid);

          printf("Creater gid: %d ",  pstShm->shm_perm.cgid);

          printf("Mode       : %#o ", pstShm->shm_perm.mode);

          printf("Seque      : %d ",  pstShm->shm_perm.__seq);

          printf(" ");

          printf("Share memory size:%d ", (int)pstShm->shm_segsz);

          printf("Last time for shmat:%d ", (int)pstShm->shm_atime);

          printf("Last time for shmdt:%d ", (int)pstShm->shm_dtime);

          printf("Last time for change:%d ", (int)pstShm->shm_ctime);

          printf("Create share memory id:%d ", (int)pstShm->shm_cpid);

          printf("last read share memory id:%d ", (int)pstShm->shm_lpid);

          printf("Current process number:%d ", (int)pstShm->shm_nattch);

          printf("--------------------------------------------- ");

    }

    //提示

    void Usage()

    {

          printf(" stat : print share memory infomation ");

          printf(" set : reset share memory mode ");

          printf(" exit : exit process ");

          return;

    }

    //设置操作

    void testShmCtl(int shmid)

    {

          Usage();

          struct shmid_ds  stShm;

          int iRet;

          char szCmd[100] = {};

          while(1)

          {

               fprintf(stderr, "->");

               scanf("%s", szCmd);

               // stat 当前属性

               if (!strcmp(szCmd, "stat"))

               {

                     iRet = shmctl(shmid, IPC_STAT, &stShm);

                     if (iRet<0)

                     {

                          perror("Fail to IPC_STAT!");

                          continue;

                     }

                     printShmInfo(&stShm);

               }

               //设置mode

               else if (!strcmp(szCmd, "set"))

               {

                     int mode;

                     iRet = shmctl(shmid, IPC_STAT, &stShm);

                     if (iRet)

                     {

                          printf("Fail to IPC_STAT!");

                          continue;

                     }

                     printf("Current Mode: %#o ", stShm.shm_perm.mode);

                     fprintf(stderr, "New Mode(eg:600):");

                     scanf("%o", &mode);

                     if (mode < 0 || mode > 0777)

                     {

                          printf("Mode is invalid(range 0 to 0777). ");

                          continue;

                     }

                     //修改模式

                     stShm.shm_perm.mode= mode;

                     //更新

                     iRet = shmctl(shmid, IPC_SET, &stShm);

                     if (iRet)

                     {

                          perror("Fail to IPC_SET!");

                          continue;

                     }

                     printf("Set mode success! ");

               }

               //退出

               else if (!strcmp(szCmd, "exit"))

               {

                     break;

               }

               else

               {

                     Usage();

               }

          }   

          //删除共享内存区域

          fprintf(stderr, "Delete share memory [%d]?(y/n):", shmid);

          scanf("%s",szCmd);

          if (!strcmp(szCmd, "y"))

          {

               iRet = shmctl(shmid, IPC_RMID, NULL);

               if (iRet)

               {

                     perror("Fail to IPC_RMID!");

                     return;

               }

               printf("Delete success! ");

          }

          return;

    }

    int main(int argc, char ** argv)

    {

          if (argc != 2 || (strcmp(argv[1], "w") && strcmp(argv[1], "r")&& strcmp(argv[1], "c" )))

          {

               printf("Usage: %s [w | r | c] ", argv[0]);

               printf(" w:  write share memory ");

               printf(" r : read share memory ");

               printf(" c : control share memory ");

               return 0;

          }

          char szFile[] = "123";

          //创建key

          key_t key = ftok(szFile, 321);

          if (key==-1)

          {

               perror("Fail to ftok!");

               return -1;

          }

          printf("KEY: %#x ", key);

          //创建共享内存

          int shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0660);

          if (shmid < 0)

          {

               perror("fail to shmget!");

               return -1;

          }

          printf("shmid: %d ", shmid);

          //写

          if (argv[1][0] == 'w')

          {

               writeMemory(shmid);

          }   

          //读

          else if(argv[1][0] == 'r')

          {

               readMemory(shmid);

          }

          //设置

          else

          {

               testShmCtl(shmid);

          }

          return 0;

    }

  • 相关阅读:
    you must restart adb and eclipse的相关解决办法
    Qt slot中获取sender
    添加开机启动项
    Unreal开发HTC Vive程序,开启VR编辑模式
    Android弹出一项权限请求
    Unreal新建C++类或C++项目失败
    win10 设置C盘访问权限
    windows系统共享设置最顺的一次
    下载Qt安装包
    单例模式
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/9216023.html
Copyright © 2020-2023  润新知