來源:http://www.rosoo.net/a/201307/16703.html
1、概念
共用記憶體:共用記憶體是進程間通信中最簡單的方式之一。共用記憶體允許兩個或更多進程訪問同一塊記憶體,就如同 malloc() 函數向不同進程返回了指向同一個實體記憶體區域的指標。當一個進程改變了這塊位址中的內容的時候,其它進程都會察覺到這個更改。
2、用途
. 共用記憶體允許兩個或多個進程共用一給定的存儲區,因為資料不需要來回複製,所以是最快的一種進程間通信機制。共用記憶體可以通過mmap()映射普通檔 (特殊情況下還可以採用匿名映射)機制實現,也可以通過系統V共用記憶體機制實現。應用介面和原理很簡單,內部機制複雜。為了實現更安全通信,往往還與信號 燈等同步機制共同使用
共用記憶體涉及到了存儲管理以及檔案系統等方面的知識,深入理解其內部機制有一定的難度,關鍵還要緊緊抓住內核使用的重要資料結構。系統V共用內 存是以檔的形式組織在特殊檔案系統shm中的。通過shmget可以創建或獲得共用記憶體的識別碼。取得共用記憶體識別碼後,要通過shmat將這個記憶體區 映射到本進程的虛擬位址空間
3、特點
共用記憶體。顧名思義,這種通信方式允許多個進程共用同一塊實體記憶體空間來實現進程之間的資訊交換,其特點是沒有中間環節,直接將共用的記憶體頁面通過 附接,映射到相互通信的進程各自的虛擬位址空間中,從而使多個進程可以直接存取同一個實體記憶體頁面,如同訪問自己的私有空間一樣(但實質上不是私有的而是 共用的)。因此這種進程間通信方式是在同一個電腦系統中的諸進程間實現通信的最快捷的方法,而它的局限性也在於此,即共用記憶體的諸進程必須共處同一個計 算機系統,有實體記憶體可以共用才行。
4、用法:
發送進程:
1.使用系統調用函數shmget()創建或者獲取指定key值的共用記憶體;
2.使用系統調用函數shmat(),將該共用記憶體附接到自己的虛擬位址空間;
3.將需要發送的資訊寫入共用記憶體,方法有以下幾種:
①. 每條資訊都以追加的方式寫入,可以使用C語言提供的字串追加函數strcat(viraddr, buffer),該函數的功能是將buffer中的字串追加到由viraddr附接的共用存儲區的尾部。其中,viraddr是請求得到的共用記憶體的地 址,buffer是使用者進程中請求的用來存放資訊的字元緩衝區。
②.每條資訊都以覆蓋的方式寫入,可以使用strcpy(viraddr,buffer)函數將buffer中的字串複製到viraddr指向的共用記憶體中,則該共用記憶體中就只有當前複製進來的資訊,以前複製的資訊被覆蓋了。
③.共用記憶體定義為數值型變數,則可以將*viraddr作為數值型變數對其進行操作。例如將其賦值為0可以使用:*viradd=0。
④.共用記憶體定義為數值型陣列,則可以將viraddr[i]作為下標變數使用。例如將其賦值為0可以使用: viradd[i]=0。
4.使用系統調用函數shmdt(),斷開共用記憶體。
接收進程:
1. 用系統調用函數shmget();創建或者獲取指定key值的共用記憶體;
2. 用系統調用函數shmat();將該共用記憶體附接到自己的程式空間;
3.將共用記憶體中的資訊輸出;或取出存放到其它資料塊中;
4.使用系統調用函數shmdt();斷開共用記憶體。
5.如果不再使用共用記憶體時,使用系統調用函數shmctl()將其撤銷,格式為:shmctl(shmid,IPC_RMID,0);
獲得一個共用存儲識別碼
#include
#include
int shmget(key_t key, size_t size,intshmflg);
功能:創建或打開一塊共用記憶體區
參數:
key:IPC鍵值
size:該共用存儲段的長度(位元組)
shmflg:用來標識函數的行為
參數:
shmflg:用來標識函數的行為
IPC_CREAT:如果不存在就創建
IPC_EXCL:如果已經存在則返回失敗
IPC_NOWAIT:調用進程會立即返回。若發生錯誤則返回-1。
SHM_R:可讀
SHM_W:可寫
傳回值:
成功:返回共用記憶體識別碼。
失敗:返回-1。
共用記憶體映射(attach)
#include
#include
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:
將一個共用記憶體段映射到調用進程的資料段中。
參數:
shmid:共用記憶體識別碼。
shmaddr:共用記憶體映射位址(若為Null則由系 統自動指定),推薦使用Null。
參數:
shmflg:共用記憶體段的存取權限和映射條件
0:共用記憶體具有可讀可寫許可權。
SHM_RDONLY:唯讀。
SHM_RND:(shmaddr非空時才有效)
沒有指定SHM_RND則此段連接到shmaddr所指定的位址上(shmaddr必需頁對齊)。
指定了SHM_RND則此段連接到shmaddr- shmaddr%SHMLAB 所表示的位址上。
傳回值:
成功:返回共用記憶體段首位址
失敗:返回 -1
解除共用記憶體映射(detach)
#include
#include
int shmdt(const void *shmaddr);
功能:
將共用記憶體和當前進程分離(僅僅是斷開聯繫並不刪除共用記憶體)。
參數:
shmaddr:共用記憶體映射位址。
傳回值:
成功返回 0,失敗返回 -1。
#include
#include
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:共用記憶體空間的控制。
參數:
shmid:共用記憶體識別碼。
cmd:函數功能的控制。
buf:shmid_ds資料類型的位址,用來存放或更改訊息佇列的屬性。
參數:
cmd:函數功能的控制
IPC_RMID:刪除。
IPC_SET:設置shmid_ds參數。
IPC_STAT:保存shmid_ds參數。
SHM_LOCK:鎖定共用記憶體段(超級使用者)。
SHM_UNLOCK:解鎖共用記憶體段。
傳回值:
成功返回 0,失敗返回 -1。
5、案例
//讀: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #define BUFSZ 2048 int main(int argc, char *argv[]) { int shmid; int ret; key_t key; char *shmadd; key = ftok(".", 2012); if(key==-1) { perror("ftok"); } system("ipcs -m"); /*打開共用記憶體*/ shmid = shmget(key, BUFSZ, SHM_R|SHM_W); if(shmid < 0) { perror("shmget"); exit(-1); } /*映射*/ shmadd = shmat(shmid, Null, 0); if(shmadd < 0) { perror("shmat"); exit(-1); } /*讀共用記憶體區資料*/ printf("copy data from shared-memory\n"); printf("data = [%s]\n", shmadd); /*分離共用記憶體和當前進程*/ ret = shmdt(shmadd); if(ret < 0) { perror("shmdt"); exit(1); } else { printf("deleted shared-memory\n"); } /*刪除共用記憶體*/ shmctl(shmid, IPC_RMID, Null); system("ipcs -m"); return 0; }
//寫: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #define BUFSZ 2048 int main(int argc, char *argv[]) { int shmid; int ret; key_t key; char *shmadd; key = ftok(".", 2012); if(key == -1) { perror("ftok"); } /*創建共用記憶體*/ shmid = shmget(key, BUFSZ, SHM_R|SHM_W|IPC_CREAT); if(shmid < 0) { perror("shmget"); exit(-1); } /*映射*/ shmadd = shmat(shmid, Null, 0); if(shmadd < 0) { perror("shmat"); _exit(-1); } /*拷貝資料至共用記憶體區*/ printf("copy data to shared-memory\n"); bzero(shmadd, BUFSZ); strcpy(shmadd, "data in shared memory\n"); return 0; }
Place your comment