Linux 程序通訊之:記憶體共享(Shared Memory)
阿新 • • 發佈:2018-11-19
一、簡介
共享記憶體允許兩個程序訪問同一塊記憶體區域,它們使用同一個 key
值標記。
二、特點
優點:
通訊方便,兩個程序也是直接訪問同一塊記憶體區域,減少了資料複製的操作,速度上也有明顯優勢。
缺點:
沒有提供同步機制,往往需要我們使用其它(例如訊號)等手段實現程序的同步工作。
三、API 說明
1. 標頭檔案
#include <sys/shm.h>
2. 建立記憶體共享區
int shmget(key_t key, size_t size, int shmflg);
- key : 一個非零整數,兩個程序需保持一致,即兩個程序之間通訊的鑰匙
- size : 申請的共享區的大小,單位是位元組。需要是記憶體頁大小的整數倍
- shmflg : 同
open
函式的 mode 引數,設定檔案訪問許可權,這裡額外多出一個IPC_CREAT
和IPC_EXCL
,可與 mode 進行或操作。IPC_CREAT
表示共享區不存在則建立,IPC_EXCL
和IPC_CREAT
共同使用,表示共享區已存在則返回錯誤。如0644 | IPC_CREAT
- 返回值 : 返回共享區域的 id 值,用於唯一識別該區域
3. 對映記憶體共享區
void *shmat(int shmid, const void *shmaddr, int shmflg);
at 是 attach 的意思。建立記憶體共享後,還不能被任何程序使用,需要使用該函式啟動對共享記憶體的訪問。
- shmid : 建立時候返回的 id 值
- shmaddr : 將共享記憶體對映到指定地址,可以為 NULL,此時系統將自動分配地址
- shmflg : 同 shmget 函式中的引數,通常為 0
- 返回值 : 成功執行後,返回該地址的起始地址,失敗返回 -1
4. 撤銷對映
int shmdt(const void *shmaddr);
dt 是 detach 的意思。用於將共享記憶體從該程序中分離,但並不會刪除共享記憶體。
- shmaddr : shmat 函式返回的地址
- 返回值 : 成功返回 0,失敗返回 -1,errno 將被設定為相應的值
5. 刪除記憶體共享區
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
ctl 是 control 的意思。該函式用於查詢、更新、刪除共享區域。共享記憶體不使用後必須刪除,以便回收記憶體。
- shmid : 建立時候返回的 id 值
- cmd : 控制命令。
IPC_STAT
狀態查詢IPC_SET
在許可權允許下,將共享記憶體狀態更新為 buf 中的資料IPC_RMID
刪除共享記憶體
- 返回值 : 成功返回 0,失敗返回 -1,errno 將被設定為相應的值
四、示例
1. 寫端
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main() {
void *shmaddr = NULL;
const char data[] = "Hello World\n";
int shmid;
key_t key = (key_t) 666;
long page_size = sysconf(_SC_PAGESIZE);
int data_size = (strlen(data) + page_size - 1) & (~(page_size - 1));
printf("data size: %d, page size: %ld\n", data_size, page_size);
// 1. create shared memory
shmid = shmget(key, data_size, 0644 | IPC_CREAT);
if (shmid == -1) {
perror("shmget failed\n");
exit(EXIT_FAILURE);
}
// 2. attach shared memory
shmaddr = shmat(shmid, NULL, 0);
if (shmaddr == (void *)-1) {
perror("shmat failed\n");
exit(EXIT_FAILURE);
}
// 3. write data to shared memory
memset(shmaddr, 0, data_size);
memcpy(shmaddr, &data, strlen(data));
// 4. detach shared memory
if (shmdt(shmaddr) == -1) {
perror("shmdt failed\n");
exit(EXIT_FAILURE);
}
printf("write done !\n");
return 0;
}
2. 讀端
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main() {
void *shmaddr = NULL;
const char data[] = "Hello World\n";
int shmid;
key_t key = (key_t) 666;
long page_size = sysconf(_SC_PAGESIZE);
int data_size = (strlen(data) + page_size - 1) & (~(page_size - 1));
printf("data size: %d, page size: %ld\n", data_size, page_size);
// 1. create shared memory
shmid = shmget(key, data_size, 0644 | IPC_CREAT);
if (shmid == -1) {
perror("shmget failed\n");
exit(EXIT_FAILURE);
}
// 2. attach shared memory
shmaddr = shmat(shmid, NULL, 0);
if (shmaddr == (void *)-1) {
perror("shmat failed\n");
exit(EXIT_FAILURE);
}
// 3. read data to shared memory
printf("read form shead memory: %s\n", (char *)shmaddr);
// 4. detach shared memory
if (shmdt(shmaddr) == -1) {
perror("shmdt failed\n");
exit(EXIT_FAILURE);
}
// 5. delete shared memory
if (shmctl(shmid, IPC_RMID, 0) == -1) {
perror("shmctl delete shared memory failed\n");
exit(EXIT_FAILURE);
}
return 0;
}
3. 執行結果
第一次執行寫程序,往 shared memory 中寫入了 “Hello World”,再執行讀程序,讀出並列印 shared memory 中的內容,並刪除掉共享記憶體。