Linux 程序間通訊(六)共享記憶體
可以說, 共享記憶體是一種最為高效的程序間通訊方式, 因為程序可以直接讀寫記憶體, 不需要任何資料的複製。 為了在多個程序間交換資訊, 核心專門留出了一塊記憶體區, 這段記憶體區可以由需要訪問的程序將其對映到自己的私有地址空間。 因此, 程序就可以直接讀寫這一記憶體區而不需要進行資料的複製, 從而大大提高了效率。 當然, 由於多個程序共享一段記憶體,因此也需要依靠某種同步機制, 如互斥鎖和訊號量等(請參考 4.7.2 節)。
其原理示意圖如圖4.7 所示。
共享記憶體的實現分為兩個步驟:
第一步是建立共享記憶體, 這裡用到的函式是 shmget(),也就是從記憶體中獲得一段共享記憶體區域;
第二步是對映共享記憶體, 也就是把這段建立的共享記憶體對映到具體的程序空間中, 這裡使用的函式是 shmat()。
到這裡, 就可以使用這段共享記憶體了, 也就是可以使用不帶緩衝的 I/O 讀寫命令對其進行操作。
除此之外, 還有撤銷對映的操作, 其函式為 shmdt()。 這裡主要介紹這 3 個函式。
shmget()函式的語法要點。
函式原型
int shmget(key_t key, int size, int shmflg)
功能
建立獲得共享記憶體
函式傳入值 key: 共享記憶體的鍵值, 多個程序可以通過它訪問同一個共享記憶體, 其中有個特殊值 IPC_PRIVATE, 用於建立當前程序的私有共享記憶體 size: 共享記憶體區大小 shmflg: 同 open()函式的許可權位, 也可以用八進位制表示法函式返回值
成功: 共享記憶體段識別符號 出錯: 1
shmat()函式的語法要點。
函式原型
char *shmat(int shmid, const void *shmaddr, int shmflg)函式傳入值 shmid: 要對映的共享記憶體區識別符號 shmaddr: 將共享記憶體對映到指定地址(若為 0 則表示系統自動分配地址並把該段共享記憶體對映到呼叫程序的地址空間) shmflg:
- SHM_RDONLY: 共享記憶體只讀
- 預設 0: 共享記憶體可讀寫
函式返回值 成功: 被對映的段地址 出錯: 1
shmdt()函式的語法要點。
函式原型 int shmdt(const void *shmaddr)函式引數
shmaddr: 被對映的共享記憶體段地址
函式返回值 成功: 0 出錯: 1
shmctl()函式的語法要點。
函式原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能
對已存在的共享記憶體進行控制
函式引數
shmid:共享記憶體標識
cmd:操作型別
buf:指向操作的資訊
返回值
成功返回0,否則返回-1
cmd | 含義 |
IPC_STAT | 獲取共享記憶體的狀態 |
IPC_SET | 設定共享記憶體的許可權 |
IPC_RMID | 刪除共享記憶體 |
SHM_LOCK | 鎖定共享記憶體,使共享記憶體不被置換出去 |
SHM_UNLOCK | 對共享記憶體 解鎖 |
重要結構體:
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; /* 建立程序ID */
pid_t shm_lpid; /* 最近操作的程序ID */
shmatt_t shm_nattch; /* 建立對映的程序數 */
...
};
struct ipc_perm {
key_t __key; /* Key supplied to shmget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions + SHM_DEST and
SHM_LOCKED flags */
unsigned short __seq; /* Sequence number */
};