共享記憶體基本概念
共享記憶體區是最快的IPC形式。一旦這樣的記憶體映射到共享它的程序的位址空間,這些程序間資料傳遞不再涉及到核心,換句話說是程序不再通過執行進入核心的系統調用來傳遞彼此的資料(如圖)。

共享記憶體 VS. 其他IPC形式
用管道/消息隊列傳遞資料
用共享記憶體傳遞資料
(核心為每個IPC對象維護一個資料結構)
共享記憶體生成之後,傳遞資料并不需要再走Linux核心,共享記憶體允許兩個或多個程序共享一個給定的存儲區域,資料并不需要在多個程序之間進行複制,是以,共享記憶體的傳輸速度更快!!
System V共享記憶體資料結構與基本API
[cpp] view plain copy
- //基本資料結構
- struct shmid_ds
- {
- struct ipc_perm shm_perm;
- size_t shm_segsz;
- time_t shm_atime;
- time_t shm_dtime;
- time_t shm_ctime;
- pid_t shm_cpid;
- pid_t shm_lpid;
- shmatt_t shm_nattch;
- ...
- };
共享記憶體函數
[cpp] view plain copy
- #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
原型:
[cpp] view plain copy
- <span style="font-family:Courier New;">int shmget(key_t key, size_t size, int shmflg);</span>
參數:
key:這個共享記憶體段名字
size:共享記憶體大小
shmflg:由九個權限标志構成,它們的用法和建立檔案時使用的mode模式标志是一樣的
傳回值:
成功傳回一個非負整數,即該共享記憶體段的辨別碼;失敗傳回-1
[cpp] view plain copy
- //實驗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;
- }
[cpp] view plain copy
- //實驗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;
- }
[cpp] view plain copy
- //實驗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函數
功能:将共享記憶體段連接配接到程序位址空間
原型:
[cpp] view plain copy
- 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,表示連接配接操作用來隻讀共享記憶體
[cpp] view plain copy
- //示例1
- int 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;
- }
[cpp] view plain copy
- //示例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;
- }