23共享内存

Posted gd-luojialin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;

}

 

以上是关于23共享内存的主要内容,如果未能解决你的问题,请参考以下文章

回复:共享内存和信号量

将 Boost 享元与共享内存一起使用

在共享内存中创建二维数组

如何在c中制作共享内存?

在不同步的情况下读写 SysV 共享内存(使用信号量、C/C++、Linux)

如何在 fork() 创建的进程之间共享内存?