Linux處理序間通訊——使用共用記憶體

來源:互聯網
上載者:User

標籤:linux

一、什麼是共用記憶體顧名思義,共用記憶體就是允許兩個不相關的進程訪問同一個邏輯記憶體。共用記憶體是在兩個正在啟動並執行進程之間共用和傳遞資料的一種非常有效方式。不同進程之間共用的記憶體通常安排為同一段實體記憶體。進程可以將同一段共用記憶體串連到它們自己的地址空間中,所有進程都可以訪問共用記憶體中的地址,就好像它們是由用C語言函數malloc分配的記憶體一樣。而如果某個進程向共用記憶體寫入資料,所做的改動將立即影響到可以訪問同一段共用記憶體的任何其他進程。
特別提醒:共用記憶體並未提供同步機制,也就是說,在第一個進程結束對共用記憶體的寫操作之前,並無自動機制可以阻止第二個進程開始對它進行讀取。所以我們通常需要用其他的機制來同步對共用記憶體的訪問,例如前面說到的訊號量。有關訊號量的更多內容,可以查閱我的另一篇文章:Linux處理序間通訊——使用訊號量
二、共用記憶體的使得與訊號量一樣,在Linux中也提供了一組函數介面用於使用共用記憶體,而且使用共用共存的介面還與訊號量的非常相似,而且比使用訊號量的介面來得簡單。它們聲明在標頭檔 sys/shm.h中。
1、shmget函數該函數用來建立共用記憶體,它的原型為:
int shmget(key_t key, size_t size, int shmflg);  

第一個參數,與訊號量的semget函數一樣,程式需要提供一個參數key(非0整數),它有效地為共用記憶體段命名,shmget函數成功時返回一個與key相關的共用記憶體標識符(非負整數),用於後續的共用記憶體函數。調用失敗返回-1.
不相關的進程可以通過該函數的返回值訪問同一共用記憶體,它代表程式可能要使用的某個資源,程式對所有共用記憶體的訪問都是間接的,程式先通過調用shmget函數並提供一個鍵,再由系統產生一個相應的共用記憶體標識符(shmget函數的返回值),只有shmget函數才直接使用訊號量鍵,所有其他的訊號量函數使用由semget函數返回的訊號量標識符。
第二個參數,size以位元組為單位指定需要共用的記憶體容量
第三個參數,shmflg是許可權標誌,它的作用與open函數的mode參數一樣,如果要想在key標識的共用記憶體不存在時,建立它的話,可以與IPC_CREAT做或操作。共用記憶體的許可權標誌與檔案的讀寫權限一樣,舉例來說,0644,它表示允許一個進程建立的共用記憶體被記憶體建立者所擁有的進程向共用記憶體讀取和寫入資料,同時其他使用者建立的進程只能讀取共用記憶體。
2、shmat函數第一次建立完共用記憶體時,它還不能被任何進程訪問,shmat函數的作用就是用來啟動對該共用記憶體的訪問,並把共用記憶體串連到當前進程的地址空間。它的原型如下:
void *shmat(int shm_id, const void *shm_addr, int shmflg);  


第一個參數,shm_id是由shmget函數返回的共用記憶體標識。第二個參數,shm_addr指定共用記憶體串連到當前進程中的地址位置,通常為空白,表示讓系統來選擇共用記憶體的地址。第三個參數,shm_flg是一組標誌位,通常為0。
調用成功時返回一個指向共用記憶體第一個位元組的指標,如果調用失敗返回-1.
3、shmdt函數該函數用於將共用記憶體從當前進程中分離。注意,將共用記憶體分離並不是刪除它,只是使該共用記憶體對當前進程不再可用。它的原型如下:
int shmdt(const void *shmaddr);


參數shmaddr是shmat函數返回的地址指標,調用成功時返回0,失敗時返回-1.
4、shmctl函數與訊號量的semctl函數一樣,用來控制共用記憶體,它的原型如下:
int shmctl(int shm_id, int command, struct shmid_ds *buf);



第一個參數,shm_id是shmget函數返回的共用記憶體標識符。
第二個參數,command是要採取的操作,它可以取下面的三個值 :    IPC_STAT:把shmid_ds結構中的資料設定為共用記憶體的當前關聯值,即用共用記憶體的當前關聯值覆蓋shmid_ds的值。    IPC_SET:如果進程有足夠的許可權,就把共用記憶體的當前關聯值設定為shmid_ds結構中給出的值
    IPC_RMID:刪除共用記憶體段

第三個參數,buf是一個結構指標,它指向共用記憶體模式和存取權限的結構。shmid_ds結構至少包括以下成員:
struct shmid_ds  {      uid_t shm_perm.uid;      uid_t shm_perm.gid;      mode_t shm_perm.mode;  };  

測試案例源碼:
#include<sys/stat.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#define PERM S_IRUSR|S_IWUSRint main(int argc,char **argv){int shmid;char *p_addr,*c_addr;if(argc!=2){fprintf(stderr,"Usage:%s\n\a",argv[0]);exit(1);}if((shmid=shmget(IPC_PRIVATE,1024,PERM))==-1){fprintf(stderr,"Create Share Memory Error:%s\n\a",strerror(errno));exit(1);}if(fork()){p_addr = shmat(shmid,0,0);memset(p_addr,'\0',1024);//printf("argv= %s\n",argv[1]);strncpy(p_addr,argv[1],1024);wait(NULL);exit(0);}else{sleep(1);c_addr=shmat(shmid,0,0);printf("Client get %s\n",c_addr);exit(0);}return 1;}</span>

編譯後輸出:Client get 12345

五、使用共用記憶體的優缺點1、優點:我們可以看到使用共用記憶體進行進程間的通訊真的是非常方便,而且函數的介面也簡單,資料的共用還使進程間的資料不用傳送,而是直接存取記憶體,也加快了程式的效率。同時,它也不像匿名管道那樣要求通訊的進程有一定的父子關係。
2、缺點:共用記憶體沒有提供同步的機制,這使得我們在使用共用記憶體進行處理序間通訊時,往往要藉助其他的手段來進行進程間的同步工作。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.