Linux 進程間通訊 共享內存

1.特色:
  1)共享內存是一種最爲高效的進程間通訊方式,進程能夠直接讀寫內存,而不須要任何數據的拷貝。如管道當在內核空間建立之後,用戶空間須要內存  拷貝,須要拷貝數據,因此效率低。

  2)爲了在多個進程間交換信息,內核專門留出了一塊內存區,能夠由須要訪問的進程將其映射到本身的私有地址空間app

  3)進程就能夠直接讀寫這一內存區而不須要進行數據的拷貝,從而大大提升的效率。函數

  4)因爲多個進程共享一段內存,所以也須要依靠某種同步機制,如互斥鎖和信號量等測試

 

2.共享內存的使用步驟:spa

  1)建立/打開共享內存code

  2)映射共享內存。即把指定的共享內存映射到進程的地址空間用於訪問對象

  3)撤銷共享內存映射blog

  4)刪除共享內存對象進程

3.相關函數:ip

  1)key_t ftok(const char *pathname,  int proj_id);內存

    功能:產生一個獨一無二的key值

    參數:Pathname:已經存在的且可訪問文件的名字

       Proj_id:一個字符(由於只用低8位),生成key的數字,不能爲0

    返回值:成功:key值;失敗:-1

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

    功能:建立或打開共享內存對象

    參數:key 鍵值 ; size 共享內存的大小 ; shmflg IPC_CREAT|IPC_EXCL|0777(標誌位,是否新建,和權限)

    返回值:成功 shmid(共享內存ID) ; 出錯 -1

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

    功能:映射共享內存,即把指定的共享內存映射到進程的地址空間用於訪問

    參數:shmid 共享內存的id號 ; shmaddr 通常爲NULL,表示由系統自動完成映射,若是不爲NULL,那麼有用戶指定

             shmflg:SHM_RDONLY就是當前進程對該共享內存只能進行讀操做  0 可讀可寫

    返回值:成功:完成映射後的地址,出錯:-1的地址

    用法:(p = (char *)shmat(shmid,NULL,0)) == (char *)-1  (對-1強轉成字符型地址)

  4)int shmdt(const void *shmaddr);

    功能:取消映射

    參數:要取消的地址

    返回值:成功0 ;失敗的-1

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

    功能:(刪除共享內存),對共享內存進行各類操做

    參數:shmid 共享內存的id號 ; cmd IPC_STAT 得到shmid屬性信息,存放在第三參數

          IPC_SET 設置shmid屬性信息,要設置的屬性放在第三參數

          IPC_RMID:刪除共享內存,此時第三個參數爲NULL便可

    返回: 成功0 ; 失敗-1

    用法:shmctl(shmid,IPC_RMID,NULL);

補充:

一、IPC對象建立後一直存在,直到被顯示的刪除,及最後一個進程要刪除IPC對象

二、每一個IPC對象除了有ID以外還有相關聯的key值(IPC對象的屬性),key值做用,經過key值,不一樣的進程可以找到打開同一個IPC對象,由於IPC對象建立好之後,他的ID是隨機分配的,只有建立IPC對象的進程才能直接得到這個ID,其餘進程是不知道這個ID的,其餘進程就經過key去得到這個ID,經過key打開同一個IPC對象。key值爲0表示私有的。不一樣的進程用ftok函數,生成的key值要同樣,及ftok函數的參數就要保持一致。

例子:

經過終端輸入信息,寫入到共享內存中,而後打印共享內存中的數據

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

int main(int argc, const char *argv[])
{
    key_t key; //共享內存的惟一標識 key 值
    int shmid; //
    char *p = NULL;

    //  函數原型  key_t ftok(const char *pathname, int proj_id);;
    key = ftok("./app",'a'); //建立key值
    if(key < 0)
    {
        perror("fail ftok ");
        exit(1);
    }//共享內存 不存在,建立
    shmid = shmget(key,128,IPC_CREAT|IPC_EXCL|0777);// 建立/打開共享內存,返回id根據id映射
    if(shmid < 0) 
    {
        if(errno == EEXIST)//文件存在時,直接打開文件獲取shmid
        {
            printf("file eexist");
            shmid = shmget(key,128,0777); //若是建立了,直接打開
        }
        else
        {
            perror("shmget fail ");
            exit(1);
        }
    }
    p = (char *)shmat(shmid,NULL,0);//映射,返回地址,根據地址操做,錯誤 返回 -1 的地址
    if( p == (char *)(-1) ) //錯誤形式判斷
    {
        perror("shmat fail ");
        exit(1);
    }

    read(0,p,10);//從終端讀數據,寫入p指向的空間
    printf("%s\n",p); //打印p指向空間的內容

    shmdt(p);//解除映射

    //int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    shmctl(shmid,IPC_RMID,NULL); //刪除

    return 0;
}

測試:終端輸入123 寫入共享內存中,而後經過共享內存打印出來

 

共享內存總結;

 (1)key 值得獲取,根據不一樣的key值得到這塊共享內存惟一的id 根據這個惟一的 id 不一樣進程實現共同訪問這塊共享內存(進程間想訪問同一塊共享內存,就要獲得這個共享內存惟一的id)

 (2) key值經過函數 ftok 函數獲取,函數的功能是根據不一樣的文件名,不一樣的字符獲得這個不一樣的 key 值

 (3) 固然這個key值其實就是一個整數,也能夠經過給定肯定的數建立 / 打開一塊共享內存,使用 ftok 的目的是防止本身亂填數字,形成不一樣進程間訪問衝突

相關文章
相關標籤/搜索