天天看點

23共享記憶體

共享記憶體

是最快的IPC通信方式,不存在資料複制,而是直接記憶體讀寫

涉及到多個程序通路,可能出現同時讀、寫操作,一般采用信号量的方式,進行互斥操作

23共享記憶體

步驟:

記憶體共享使用

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 ‘巨頁’記憶體

23共享記憶體

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)

分離連接配接到程序位址空間的共享記憶體, 釋放共享記憶體

共享記憶體設定

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..\n");

           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)

      INFO_S *pstAddr;

           //讀取指定位置内容

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

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

           //讀取

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

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

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

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

      return  ;

// shmid_ds屬性

void printShmInfo(struct shmid_ds* pstShm)

      printf("----------------- SHMID_DS  -----------------\n");

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

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

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

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

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

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

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

      printf("\n");

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

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

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

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

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

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

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

      printf("---------------------------------------------\n");

//提示

void Usage()

      printf("\tstat : print share memory infomation\n");

      printf("\tset : reset share memory mode\n");

      printf("\texit : exit process\n");

      return;

//設定操作

void testShmCtl(int shmid)

      Usage();

      struct shmid_ds  stShm;

      int iRet;

      char szCmd[100] = {};

           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;

                 if (iRet)

                      printf("Fail to IPC_STAT!");

                 printf("Current Mode: %#o\n", 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).\n");

                 //修改模式

                 stShm.shm_perm.mode= mode;

                 //更新

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

                      perror("Fail to IPC_SET!");

                 printf("Set mode success!\n");

           //退出

           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!\n");

      }

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]\n", argv[0]);

           printf("\t w:  write share memory\n");

           printf("\t r : read share memory\n");

           printf("\t c : control share memory\n");

           return 0;

      char szFile[] = "123";

      //建立key

      key_t key = ftok(szFile, 321);

      if (key==-1)

           perror("Fail to ftok!");

           return -1;

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

      //建立共享記憶體

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

      if (shmid < 0)

           perror("fail to shmget!");

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

      //寫

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

           writeMemory(shmid);

      //讀

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

           readMemory(shmid);

      //設定

      else

           testShmCtl(shmid);

      return 0;