1. 程式人生 > >最快的程序間通訊方式你get了麼

最快的程序間通訊方式你get了麼

  前言:天下武功為快不破!在資訊爆炸、快速發展的新時代...,扯遠了...。程序間通訊方式有很多,但最快的方式你知道麼?由我娓娓道來...

  一、共享記憶體方式

  主角閃亮登場了,噔噔瞪...,最快的方式就是共享記憶體了。實現共享記憶體的方式主要有兩種:

  1. 儲存對映I/O mmap函式實現
  2. shmget函式

   感覺學兩個以上相同的知識時,就會學他們的區別,我也會避免不了進入俗套,也要簡單來說它們的區別:

  

 注:此圖引自《unix環境高階程式設計》 

  看到圖片中“主要區別”四個大字了麼?別告訴我:你近視看不到,打死你個龜孫!開玩笑啦,哈哈哈!只希望在學習知識時,不要感覺太乏味哦。在下文介紹完兩種方式之後,你就會不明白它們的區別了。

  二、mmap函式實現共享記憶體

  1、儲存對映I/O

   先來畫個見圖來介紹一下實現原理,如下圖:  PS:依舊是全部落格園最醜圖,不接受反駁!!!

  

  mmap函式主要作用就是將磁碟檔案對映到記憶體中,並返回這段記憶體的首地址,並可以將這塊記憶體來當做“陣列”來處理。要對這個圖有一個模型(雖然是全部落格園最醜圖),對接下來的講解有一定幫助。

  2、mmap函式及相關函式

  原型:void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

返回:成功:返回建立的對映區首地址;失敗:

MAP_FAILED巨集,注意錯誤跟普通的不一樣!

引數說明:    

         addr:       建立對映區的首地址,由Linux核心指定。使用時,直接傳遞NULL

         length: 欲建立對映區的大小

         prot:      對映區許可權PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE

         flags:     標誌位引數(常用於設定更新物理區域、設定共享、建立匿名對映區)

                          MAP_SHARED:  會將對映區所做的操作反映到物理裝置(磁碟)上。

                          MAP_PRIVATE: 對映區所做的修改不會反映到物理裝置。

         fd:         用來建立對映區的檔案描述符

         offset: 對映檔案的偏移(4k的整數倍)

   3、munmap函式

  原型:int munmap(void *addr, size_t length); 成功:0; 失敗:-1

  功能:同malloc函式申請記憶體空間類似的,mmap建立的對映區在使用結束後也應呼叫類似free的函式來釋放。

  4、父子程序用mmap示例程式

  程式主要用共享記憶體進行通訊,如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>

int var = 100;

int main(void)
{
    int *p;
    pid_t pid;

    int fd;
    fd = open("temp", O_RDWR|O_CREAT|O_TRUNC, 0644);
    if(fd < 0){
        perror("open error");
        exit(1);
    }
    unlink("temp");                //刪除臨時檔案目錄項,使之具備被釋放條件.
    ftruncate(fd, 4);

    //p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
    if(p == MAP_FAILED){        //注意:不是p == NULL
        perror("mmap error");
        exit(1);
    }
    close(fd);                    //對映區建立完畢,即可關閉檔案

    pid = fork();                //建立子程序
    if(pid == 0){
        *p = 2000;
        var = 1000;
        printf("child, *p = %d, var = %d\n", *p, var);
    } else {
        sleep(1);
        printf("parent, *p = %d, var = %d\n", *p, var);
        wait(NULL);

        int ret = munmap(p, 4);                //釋放對映區
        if (ret == -1) {
            perror("munmap error");
            exit(1);
        }
    }

    return 0;
}
View Code

  三、匿名對映

  1、說明

通過使用我們發現使用對映區來完成檔案讀寫操作十分方便父子程序間通訊也較容易但缺陷是每次建立對映區一定要依賴一個檔案才能實現。通常為了建立對映區要open一個temp檔案,建立好了再unlinkclose掉,比較麻煩。 可以直接使用匿名對映來代替。其實Linux系統給我們提供了建立匿名對映區的方法無需依賴一個檔案即可建立對映區同樣需要藉助標誌位引數flags來指定

  使用MAP_ANONYMOUS (MAP_ANON), 如:

  int *p = mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);

     "4"隨意舉例,該位置表大小,可依實際需要填寫。

    需注意的是,MAP_ANONYMOUSMAP_ANON這兩個巨集是Linux作業系統特有的巨集。在類Unix系統中如無該巨集定義,可使用如下兩步來完成匿名對映區的建立。

  ① fd = open("/dev/zero", O_RDWR);

  ② p = mmap(NULL, size, PROT_READ|PROT_WRITE, MMAP_SHARED, fd, 0);

  2、用"/dev/sero"示例匿名對映

  程式如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

int main(void)
{
    int *p;
    pid_t pid;
    
    int fd;
    fd = open("/dev/zero", O_RDWR);

    p = mmap(NULL, 400, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);

    if(p == MAP_FAILED){        //注意:不是p == NULL
        perror("mmap error");
        exit(1);
    }

    pid = fork();                //建立子程序
    if(pid == 0){
        *p = 2000;
        printf("child, *p = %d\n", *p);
    } else {
        sleep(1);
        printf("parent, *p = %d\n", *p);
    }

    munmap(p, 4);                //釋放對映區

    return 0;
}
View Code

  總結:shmget函式會在另一篇部落格介紹,歡迎評論交流