LINUX處理序間通訊之共用儲存講解,linux進程通訊講解
LINUX處理序間通訊一、匿名管道與具名管道二、訊息佇列三、共用儲存
共用儲存概述:共用儲存允許兩個或更多進程共用一給定的儲存區。共用記憶體區是最快的IPC形式,一旦這樣的記憶體映射到共用它的進程的 地址空間,這些進程間資料傳遞不再涉及到核心,也就是說進程不再需要切換到核心態來傳遞資料。所以比起訊息佇列一直在使用者態和核心態的切換,共用儲存更高效。相關命令:
ipcs -m :查看當前核心中的共用記憶體段;
ipcrm -m +shmid :刪除對應shmid的共用記憶體段
共用記憶體:
也就是說:進程同時拿到同一片共用儲存區的shmid,使用shmat將對應的共用儲存空間串連到自己的進程地址空間,在進行操作完成之後,再使用shmdt中斷連線。在整體使用過程中不需要多次進行狀態切換。共用記憶體資料結構:
函數介紹:一、shmget:獲得共用儲存標識符
#include #include int shmget(key_t key, size_t size, int shmflg);//傳回值:成功返回共用記憶體的標識符,失敗返回-1
參數介紹:①key:與訊息佇列相同,都是由ftok函數產生;②size:共用記憶體大小(單位/位元組);通常將其向上取為系統頁長的整數倍;③shmflg:用法和建立檔案使用的mode模式標誌一樣。可參考訊息佇列中的介紹。二、shmctl: 控制共用記憶體
#include #include int shmctl(int shmid, int cmd, struct shmid_ds *buf);//成功返回0,失敗返回-1
參數介紹:①shmid:需要進行操作的共用記憶體標識碼;②cmd:需要進行的操作(分為IPC_STAT,IPC_SET,IPC_RMID)③buf:一個指向shmid_ds結構體類型的結構體指標,當參數為IPC_STAT和IPC_SET時,需要給定一個結構體,用來指定修改的值。三、shmat:將共用記憶體段串連到進程地址空間
#include #include void *shmat(int shmid, const void *shmaddr, int shmflg);//傳回值:成功返回指向共用記憶體第一個位元組的指標,失敗返回-1
參數介紹:①shmid:之前由ftok產生的共用記憶體標識符;②shmaddr:指定串連的地址;③shmflg:可取SHM_RND和SHM_RDONLY
shmaddr取值為NULL,核心自動選擇一個地址shmaddr不為NULL,且shmflg無SHM_RND標記,則以shmaddr為串連地址;shmaddr不為NULL,且shmflg設定了SHM_RND標記,則串連的地址會自動向下調整為SHMLBA的整數倍shmflg = SHM_RDONLY:表示串連操作用來唯讀共用記憶體。
註:更詳細的介紹可自行man或查看《unix環境進階編程》四、shmdt:將共用記憶體段與當前進程脫離
#include #include void *shmat(int shmid, const void *shmaddr, int shmflg); int shmdt(const void *shmaddr);//傳回值:成功返回0,失敗返回-1
參數介紹:shmaddr:由shmat所返回的指標。注意:1、共用記憶體無同步互斥機制!!2、共用記憶體段隨核心,所以我們最好是在進程結束之前不再使用時,就斷開與共用記憶體的串連。樣本:通過一片共用記憶體儲存區,client向其中寫資料,server讀取資料並列印到螢幕上。
/**********comm.h*************/#pragma once#include #include #include #include #define PATHNAME "."#define PROJ_ID 0x66int createShm(int size);int destroyShm(int shmid);int getShm(int size);/**********comm.c**********/#include "comm.h"int commShm(int size, int flags){ key_t key = ftok(PATHNAME, PROJ_ID); if(key < 0){ perror("ftok"); return -1; } int shmid = shmget(key, size, flags); if(shmid < 0){ perror("shmget"); return -2; } return shmid;}int destroyShm(int shmid){ if(shmctl(shmid, IPC_RMID, NULL) < 0){ perror("shmctl"); return -1; } return 0;}int creatShm(int size){ return commShm(size, IPC_CREAT | IPC_EXCL | 0666);}int getShm(int size){ return commShm(size, IPC_CREAT);}/**********client.c********/#include "comm.h"int main(){ int shmid = getShm(4094); char* addr = shmat(shmid, NULL, 0); sleep(1); int i = 0; while(i < 5){ addr[i] = 'A' +i; i++; addr[i] = 0; sleep(1); } shmdt(addr); sleep(2); return 0;}/*********server.c*******/#include "comm.h"int main(){ int shmid = creatShm(4096); char* addr = (char*)shmat(shmid, NULL, 0); sleep(5); int i = 0; while(i < 10){ i++; printf("client> %s\n",addr); sleep(1); } shmdt(addr); sleep(2); destroyShm(shmid); return 0;}/*******Makefile********/.PHONY : allall : server clientserver : server.c comm.c gcc $^ -o $@client : client.c comm.c gcc $^ -o $@.PHONY : cleanclean: rm server client
運行結果:開啟server端,再開啟client端,經過sleep後,client端向共用記憶體中寫入資料,server端不斷讀取,但是當client端停止寫入時,共用記憶體區的資料還是最後一次寫入的資料,所以又多輸出5次。