標籤:linux ipc 共用記憶體 處理序間通訊 進階編程
共用記憶體基本概念
共用記憶體區是最快的IPC形式。一旦這樣的記憶體映射到共用它的進程的地址空間,這些進程間資料傳遞不再涉及到核心,換句話說是進程不再通過執行進入核心的系統調用來傳遞彼此的資料()。
共用記憶體 VS. 其他IPC形式
用管道/訊息佇列傳遞資料
用共用記憶體傳遞資料
(核心為每個IPC對象維護一個資料結構)
共用記憶體產生之後,傳遞資料並不需要再走Linux核心,共用記憶體允許兩個或多個進程共用一個給定的儲存地區,資料並不需要在多個進程之間進行複製,因此,共用記憶體的傳輸速度更快!!
System V共用記憶體資料結構與基本API
//基本資料結構struct shmid_ds{ struct ipc_perm shm_perm; /* Ownership and permissions */ size_t shm_segsz; /* Size of segment (bytes) */ time_t shm_atime; /* Last attach time */ time_t shm_dtime; /* Last detach time */ time_t shm_ctime; /* Last change time */ pid_t shm_cpid; /* PID of creator */ pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */ shmatt_t shm_nattch; /* No. of current attaches */ ...};
共用記憶體函數
#include <sys/ipc.h>#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);void *shmat(int shmid, const void *shmaddr, int shmflg);int shmdt(const void *shmaddr);int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmget函數
功能:建立共用記憶體,並將該記憶體的內容初始化為0
原型:
int shmget(key_t key, size_t size, int shmflg);
參數:
key:這個共用記憶體段名字
size:共用記憶體大小
shmflg:由九個許可權標誌構成,它們的用法和建立檔案時使用的mode模式標誌是一樣的
傳回值:
成功返回一個非負整數,即該共用記憶體段的標識碼;失敗返回-1
//實驗1:開啟已經存在的共用記憶體int main(){ // int shmget(key_t key, size_t size, int shmflg); //開啟已經存在的共用記憶體 int shmid = shmget(0x225,1024,0666); if (shmid == -1) { if (errno == ENOENT) { cout << "ENOENT = " << errno << endl; } err_exit("shmget error"); } return 0;}
//實驗2:共用記憶體如若存在,則直接使用;若不存在,則建立. [IPC_CREAT選項作用]int main(){ // int shmget(key_t key, size_t size, int shmflg); int shmid = shmget(0x225,1024,0666|IPC_CREAT); if (shmid == -1) { if (errno == ENOENT) { cout << "ENOENT = " << errno << endl; } err_exit("shmget error"); } else { cout << "shmid = " << shmid << endl; } return 0;}
//實驗3:共用記憶體如果沒有,則建立;如果存在,則返回錯誤. [IPC_CREAT|IPC_EXCL組合作用]int main(){ // int shmget(key_t key, size_t size, int shmflg); int shmid = shmget(0x225,1024,0666|IPC_CREAT|IPC_EXCL); if (shmid == -1) { if (errno == ENOENT) { cout << "ENOENT = " << errno << endl; } else if (errno == EEXIST) { cout << "File is exits... EEXIST = " << errno << endl; } err_exit("shmget error"); } else { cout << "shmid = " << shmid << endl; } return 0;}
shmat函數
功能:將共用記憶體段串連到進程地址空間
原型:
void *shmat(int shmid, const void *shmaddr, int shmflg);
參數:
shmid: 共用記憶體標識
shmaddr:指定串連的地址
shmflg:它的兩個可能取值是SHM_RND和SHM_RDONLY
傳回值:
成功返回一個指標,指向共用記憶體第一個節;失敗返回-1
Shmaddr與shmflg組合說明
shmaddr為NULL,Linux內和將自動為進程串連到該記憶體(推薦使用)
shmaddr不為NULL且shmflg無SHM_RND標記,則以shmaddr為串連地址。
shmaddr不為NULL且shmflg設定了SHM_RND標記,則串連的地址會自動向下調整為SHMLBA的整數倍。公式:shmaddr - (shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示串連操作用來唯讀共用記憶體
//樣本1int main(){ // int shmget(key_t key, size_t size, int shmflg); //擷取或者開啟共用記憶體 int shmid = shmget(0x1576422, sizeof(Student), 0666 | IPC_CREAT); if (shmid == -1) { err_exit("shmget error"); } //將ID為shmid的共用記憶體串連到該進程 Student *pStudent = static_cast<Student *>(shmat(shmid, NULL, 0)); //向記憶體中寫入資料 Student studentA = {"xiaofang",2012}; memcpy(pStudent,&studentA,sizeof(Student)); cout << pStudent ->name << " " << pStudent ->number << endl; //亦可擷取該記憶體內容(其實跟本地記憶體沒有什麼區別) Student *pNewStudent = pStudent; cout << pNewStudent -> name << " " << pNewStudent -> number << endl; return 0;}
//樣本2:將共用記憶體當成數組int main(){ // int shmget(key_t key, size_t size, int shmflg); //擷取或者開啟共用記憶體 int shmid = shmget(0x15764221, 1024 * sizeof(int), 0666 | IPC_CREAT); if (shmid == -1) { err_exit("shmget error"); } //將ID為shmid的共用記憶體串連到該進程 int *pArray = static_cast<int *>(shmat(shmid, NULL, 0)); if (pArray == (void *)-1) { err_exit("shmat error"); } for (int i = 0; i != 1024; ++i) { pArray[i] = i+1; } for (int i = 0; i != 1024; ++i) { cout << pArray[i] << endl; } return 0;}
Linux共用記憶體實踐(1)