天天看點

Linux程序通信之共享記憶體

擁有夢想是一種智力,實作夢想是一種能力

概述

若是一個多線程的程序,由于各個線程共享一個位址空間,可以直接通過變量的形式進行通信。而程序,由于各個程序獨占一個位址空間,我們需要一種通信機制來完成程序間的資料互動。本章介紹的是共享記憶體,程序間的通信機制有以下幾種:

無名管道(pipe)

有名管道 (fifo)

信号(signal)

System  V  IPC

共享記憶體(share memory)

消息隊列(message queue)

信号燈集(semaphore set)

套接字(socket)

之間有區分與各自的運用場景,其中套接字通常使用在網絡服務,其他隻能在本地場景下使用。筆者以後會逐一學習,本章介紹System  V  IPC中的共享記憶體。

System  V  IPC

System  V IPC引入了三種進階程序間的通信機制。一個IPC對象包含消息隊列、共享内寸和信号量。

  • 共享記憶體
  • 消息隊列
  • 信号燈集

System V IPC對象

每個IPC對象有唯一的ID

IPC對象建立後一直存在,直到被顯式地删除

每個IPC對象有一個關聯的KEY(其中程序的私有對象KTY值為0)

Linux程式通信之共享記憶體

指令檢視IPC對象

IPC對象是全局對象,可用ipcs,ipcrm等指令檢視或删除

ipcs -q: 隻顯示消息隊列

ipcs -s: 隻顯示信号量

ipcs -m: 隻顯示共享記憶體

ipcs –help: 其他的參數

函數操作

建立一個IPC對象

程序建立IPC對象之前,先ftok生成一個key值。

 #include  <sys/types.h>

 #include <sys/ipc.h>

 key_t  ftok(const char *path,  int proj_id);

  •  成功時傳回合法的key值,失敗時傳回EOF
  •  path  存在且可通路的檔案的路徑
  •  proj_id  用于生成key的數字,不能為0

特點

  • 共享記憶體是一種最為高效的程序間通信方式,程序可以直接讀寫記憶體,而不需要任何資料的拷貝
  • 共享記憶體在核心空間建立,可被程序映射到使用者空間通路,使用靈活
  • 由于多個程序可同時通路共享記憶體,是以需要同步和互斥機制配合使用

共享記憶體使用步驟

  1. 建立/打開共享記憶體
  2. 映射共享記憶體,即把指定的共享記憶體映射到程序的位址空間用于通路
  3. 讀寫共享記憶體
  4. 撤銷共享記憶體映射
  5. 删除共享記憶體對象

shmget 建立共享記憶體

 #include <sys/ipc.h>

 #include <sys/shm.h>

 int shmget(key_t key, int size, int shmflg);

  •  成功時傳回共享記憶體的id,失敗時傳回EOF
  •  key  和共享記憶體關聯的key,IPC_PRIVATE 或 ftok生成
  •  shmflg 共享記憶體标志位  IPC_CREAT|0666

shmat 共享記憶體映射

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

  成功時傳回映射後的位址,失敗時傳回(void *)-1

  shmid   要映射的共享記憶體id

  shmaddr   映射後的位址, NULL表示由系統自動映射

  shmflg   标志位  0表示可讀寫;SHM_RDONLY表示隻讀

共享記憶體讀寫

通過指針通路共享記憶體,指針類型取決于共享記憶體中存放的資料類型

例如

      char *addr;

      int  shmid;

      ……

      if ((addr = (char *)shmat(shmid, NULL, 0)) == (char *)-1) {//映射

         perror(“shmat”);

         exit(-1);

      }

      fgets(addr, N, stdin);//從終端讀資料到記憶體

shmdt撤銷映射

 int  shmdt(void *shmaddr);
  •   成功時傳回0,失敗時傳回EOF
  •   不使用共享記憶體時應撤銷映射
  •   程序結束時自動撤銷

shmctl記憶體控制

 int  shmctl(int shmid, int cmd, struct shmid_ds *buf);
  •   shmid   要操作的共享記憶體的id
  •   cmd   要執行的操作  IPC_STAT  IPC_SET  IPC_RMID
  •   buf   儲存或設定共享記憶體屬性的位址

如果要删除記憶體

示例

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>  
#include <sys/ipc.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
  key_t key;
  char *addr;
  int  shmid;
  
  if ((key = ftok(“.”, ‘a’)) == -1) 
  {
    perror(“key”);
    exit(-1);
  }   

  if ((shmid = shmget(key, 1024, IPC_CREAT|0666)) < 0) 
  {
    perror(“shmget”);
    exit(-1);
  }
     
  if ((addr = (char *)shmat(shmid, NULL, 0)) == (char *)-1)
  {
    perror(“shmat”);
    exit(-1);
  }
  
  fgets(addr, N, stdin);
  shmdt(addr);
  shmctl(shmid, IPC_RMID, NULL);

  return 0;
}