擁有夢想是一種智力,實作夢想是一種能力
概述
若是一個多線程的程序,由于各個線程共享一個位址空間,可以直接通過變量的形式進行通信。而程序,由于各個程序獨占一個位址空間,我們需要一種通信機制來完成程序間的資料互動。本章介紹的是共享記憶體,程序間的通信機制有以下幾種:
無名管道(pipe)
有名管道 (fifo)
信号(signal)
System V IPC
共享記憶體(share memory)
消息隊列(message queue)
信号燈集(semaphore set)
套接字(socket)
之間有區分與各自的運用場景,其中套接字通常使用在網絡服務,其他隻能在本地場景下使用。筆者以後會逐一學習,本章介紹System V IPC中的共享記憶體。
System V IPC
System V IPC引入了三種進階程序間的通信機制。一個IPC對象包含消息隊列、共享内寸和信号量。
- 共享記憶體
- 消息隊列
- 信号燈集
System V IPC對象
每個IPC對象有唯一的ID
IPC對象建立後一直存在,直到被顯式地删除
每個IPC對象有一個關聯的KEY(其中程序的私有對象KTY值為0)

指令檢視IPC對象
IPC對象是全局對象,可用ipcs,ipcrm等指令檢視或删除
ipcs -q: 隻顯示消息隊列
ipcs -s: 隻顯示信号量
ipcs -m: 隻顯示共享記憶體
ipcs –help: 其他的參數
函數操作
建立一個IPC對象
程序建立IPC對象之前,先ftok生成一個key值。
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *path, int proj_id);
- 成功時傳回合法的key值,失敗時傳回EOF
- path 存在且可通路的檔案的路徑
- proj_id 用于生成key的數字,不能為0
特點
- 共享記憶體是一種最為高效的程序間通信方式,程序可以直接讀寫記憶體,而不需要任何資料的拷貝
- 共享記憶體在核心空間建立,可被程序映射到使用者空間通路,使用靈活
- 由于多個程序可同時通路共享記憶體,是以需要同步和互斥機制配合使用
共享記憶體使用步驟
- 建立/打開共享記憶體
- 映射共享記憶體,即把指定的共享記憶體映射到程序的位址空間用于通路
- 讀寫共享記憶體
- 撤銷共享記憶體映射
- 删除共享記憶體對象
shmget 建立共享記憶體
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, int size, int shmflg);
- 成功時傳回共享記憶體的id,失敗時傳回EOF
- key 和共享記憶體關聯的key,IPC_PRIVATE 或 ftok生成
- shmflg 共享記憶體标志位 IPC_CREAT|0666
shmat 共享記憶體映射
void *shmat(int shmid, const void *shmaddr, int shmflg);
成功時傳回映射後的位址,失敗時傳回(void *)-1
shmid 要映射的共享記憶體id
shmaddr 映射後的位址, NULL表示由系統自動映射
shmflg 标志位 0表示可讀寫;SHM_RDONLY表示隻讀
共享記憶體讀寫
通過指針通路共享記憶體,指針類型取決于共享記憶體中存放的資料類型
例如
char *addr;
int shmid;
……
if ((addr = (char *)shmat(shmid, NULL, 0)) == (char *)-1) {//映射
perror(“shmat”);
exit(-1);
}
fgets(addr, N, stdin);//從終端讀資料到記憶體
shmdt撤銷映射
int shmdt(void *shmaddr);
- 成功時傳回0,失敗時傳回EOF
- 不使用共享記憶體時應撤銷映射
- 程序結束時自動撤銷
shmctl記憶體控制
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- shmid 要操作的共享記憶體的id
- cmd 要執行的操作 IPC_STAT IPC_SET IPC_RMID
- buf 儲存或設定共享記憶體屬性的位址
如果要删除記憶體
示例
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
key_t key;
char *addr;
int shmid;
if ((key = ftok(“.”, ‘a’)) == -1)
{
perror(“key”);
exit(-1);
}
if ((shmid = shmget(key, 1024, IPC_CREAT|0666)) < 0)
{
perror(“shmget”);
exit(-1);
}
if ((addr = (char *)shmat(shmid, NULL, 0)) == (char *)-1)
{
perror(“shmat”);
exit(-1);
}
fgets(addr, N, stdin);
shmdt(addr);
shmctl(shmid, IPC_RMID, NULL);
return 0;
}