共享記憶體
是最快的IPC通信方式,不存在資料複制,而是直接記憶體讀寫
涉及到多個程序通路,可能出現同時讀、寫操作,一般采用信号量的方式,進行互斥操作
步驟:
記憶體共享使用
1: ftok 使用某個檔案做關鍵字建立key
2: shmget 使用key 建立(打開)共享記憶體 shmid
3: shmat 打開(映射)共享記憶體. (attach)
4: memcpy 使用(讀寫)共享記憶體
5: shmdt 釋放共享記憶體. (detach)
6: shmctl 删除共享記憶體
建立共享記憶體
<sys/ipc.h>
<sys/shm.h>
int shmget(key_t key, size_t sz, int shmflg)
參數:
key ftok結果或者 IPC_PRIVATE
sz 共享記憶體的大小
shmflg IPC_CREAT | IPC_EXCL | 通路權限
SHM_HUGETLB 記憶體配置設定 HUGETLB ‘巨頁’記憶體
shmat
void *shmat(int shmid, void* shmaddr, int shmflg)
将共享記憶體連接配接到指定的程序位址空間,使用共享記憶體
shmid 共享記憶體id
shmaddr 連接配接的記憶體位址
NULL: 系統自動選擇合适的記憶體位址(推薦)
非NULL: shmflg 指定 SHM_RND,
把位址減去部分取SHMLBA整數倍
shmaddr – (shmaddr % SHMLBA)
shmflg SHM_RND
SHM_RDONLY 隻讀通路
注意:函數出錯傳回 -1, 不是NULL !!!!!!!!
shmdt
int shmdt(void *shmaddr)
分離連接配接到程序位址空間的共享記憶體, 釋放共享記憶體
共享記憶體設定
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid 共享記憶體ID
cmd 要做的操作
*buf 操作對應的資料
cmd 參數
IPC_STAT 将核心共享記憶體的相關資料讀取到 buf中
IPC_SET 将buf中的資料設定到共享記憶體
IPC_RMID 删除共享記憶體
(以下需要定義宏 _GNU_SOURCE)
IPC_INFO 擷取共享記憶體的系統限制,存入buf中
buf 指向 shminfo 結構體
SHM_INFO 擷取共享記憶體消耗的系統資源消息,存入buf中
buf 指向 shm_info 結構體(和IPC_INFO 不同)
SHM_STAT 擷取共享記憶體相關資料,同 IPC_STAT
shmid 使用核心中維護該共享記憶體數組的索引值
SHM_LOCK 鎖定共享記憶體,不允許進行交換到虛拟記憶體
SHM_UNLOCK 解鎖共享記憶體
共享記憶體資料結構
struct shmid_ds {
struct ipc_perm shm_perm;
size_t shm_segsz; //共享記憶體大小
time_t shm_atime; //最後調用shmat時間
time_t shm_dtime; //最後調用shmdt時間
time_t shm_ctime; //最後改變共享記憶體的時間
pid_t shm_cpid; //建立共享記憶體的程序
pid_t shm_lpid; //最後一次通路共享記憶體的程序
shmatt_t shm_nattch; //目前連接配接的程序數
}
共享記憶體中的資料
struct ipc_perm{
key_t key; //msgget 的key參數
uid_t uid //消息隊列所有者 euid
gid_t gid; //消息隊列所有者 egid
uid_t cuid; //消息隊列建立者 euid
gid_t cgid; //消息隊列建立者 egid
unsigned short mode; //通路權限
unsigned short __seq; //序列号
系統共享記憶體資料
struct shminfo {
unsigned long shmmax; //共享記憶體允許最大段數
unsigned long shmmin; //共享記憶體最小段數
unsigned long shmmni; //共享記憶體段最大個數
unsigned long shmseg; //程序可以通路的最大段數(未使用)
unsigned long shmall; //系統最大共享記憶體頁
struct shm_info {
int used_ids; //目前系統中存在的共享記憶體
unsigned long shm_tot; //共享記憶體總頁數
unsigned long shm_rss; //駐留的共享記憶體頁數
unsigned long shm_swp; //交換的共享記憶體頁數
unsigned long swap_attempts; //廢棄
unsigned long swap_successed; //廢棄
例子:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#define SHM_SIZE 0x100000
typedef struct tagInfo
{
char szName[16];
int age;
char szTel[16];
}INFO_S;
//寫操作
void writeMemory(int shmid)
//根據shmid連接配接共享記憶體,擷取首位址
INFO_S *pstAddr;
pstAddr=(INFO_S*)shmat(shmid,NULL,0);
INFO_S stInfo;
int pos;
while(1)
{
//共享記憶體指定位置寫入内容
fprintf(stderr,"input write pos:");
scanf("%d",&pos);
memset(&stInfo,0,sizeof(stInfo));
fprintf(stderr,"input your infomation..\n");
printf("name:");
scanf("%s",stInfo.szName);
printf("age:");
scanf("%d",&(stInfo.age));
printf("szTel:");
scanf("%s",stInfo.szTel);
//将内容放入記憶體
memcpy(pstAddr+pos,&stInfo,sizeof(stInfo));
}
shmdt(pstAddr);
return ;
void readMemory(int shmid)
INFO_S *pstAddr;
//讀取指定位置内容
fprintf(stderr,"input read pos:");
memset(&stInfo,0,sizeof(stInfo));
//讀取
memcpy(&stInfo,pstAddr+pos,sizeof(stInfo));
printf("name:%s\n",stInfo.szName);
printf("age:%d\n",stInfo.age);
printf("szTel:%s\n",stInfo.szTel);
return ;
// shmid_ds屬性
void printShmInfo(struct shmid_ds* pstShm)
printf("----------------- SHMID_DS -----------------\n");
printf("Key : %#x\n", pstShm->shm_perm.__key);
printf("Ownner uid : %d\n", pstShm->shm_perm.uid);
printf("Ownner gid : %d\n", pstShm->shm_perm.gid);
printf("Creater uid: %d\n", pstShm->shm_perm.cuid);
printf("Creater gid: %d\n", pstShm->shm_perm.cgid);
printf("Mode : %#o\n", pstShm->shm_perm.mode);
printf("Seque : %d\n", pstShm->shm_perm.__seq);
printf("\n");
printf("Share memory size:%d\n", (int)pstShm->shm_segsz);
printf("Last time for shmat:%d\n", (int)pstShm->shm_atime);
printf("Last time for shmdt:%d\n", (int)pstShm->shm_dtime);
printf("Last time for change:%d\n", (int)pstShm->shm_ctime);
printf("Create share memory id:%d\n", (int)pstShm->shm_cpid);
printf("last read share memory id:%d\n", (int)pstShm->shm_lpid);
printf("Current process number:%d\n", (int)pstShm->shm_nattch);
printf("---------------------------------------------\n");
//提示
void Usage()
printf("\tstat : print share memory infomation\n");
printf("\tset : reset share memory mode\n");
printf("\texit : exit process\n");
return;
//設定操作
void testShmCtl(int shmid)
Usage();
struct shmid_ds stShm;
int iRet;
char szCmd[100] = {};
fprintf(stderr, "->");
scanf("%s", szCmd);
// stat 目前屬性
if (!strcmp(szCmd, "stat"))
{
iRet = shmctl(shmid, IPC_STAT, &stShm);
if (iRet<0)
{
perror("Fail to IPC_STAT!");
continue;
}
printShmInfo(&stShm);
}
//設定mode
else if (!strcmp(szCmd, "set"))
int mode;
if (iRet)
printf("Fail to IPC_STAT!");
printf("Current Mode: %#o\n", stShm.shm_perm.mode);
fprintf(stderr, "New Mode(eg:600):");
scanf("%o", &mode);
if (mode < 0 || mode > 0777)
printf("Mode is invalid(range 0 to 0777).\n");
//修改模式
stShm.shm_perm.mode= mode;
//更新
iRet = shmctl(shmid, IPC_SET, &stShm);
perror("Fail to IPC_SET!");
printf("Set mode success!\n");
//退出
else if (!strcmp(szCmd, "exit"))
break;
else
Usage();
//删除共享記憶體區域
fprintf(stderr, "Delete share memory [%d]?(y/n):", shmid);
scanf("%s",szCmd);
if (!strcmp(szCmd, "y"))
iRet = shmctl(shmid, IPC_RMID, NULL);
if (iRet)
perror("Fail to IPC_RMID!");
return;
printf("Delete success!\n");
}
int main(int argc, char ** argv)
if (argc != 2 || (strcmp(argv[1], "w") && strcmp(argv[1], "r")&& strcmp(argv[1], "c" )))
printf("Usage: %s [w | r | c]\n", argv[0]);
printf("\t w: write share memory\n");
printf("\t r : read share memory\n");
printf("\t c : control share memory\n");
return 0;
char szFile[] = "123";
//建立key
key_t key = ftok(szFile, 321);
if (key==-1)
perror("Fail to ftok!");
return -1;
printf("KEY: %#x\n", key);
//建立共享記憶體
int shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0660);
if (shmid < 0)
perror("fail to shmget!");
printf("shmid: %d\n", shmid);
//寫
if (argv[1][0] == 'w')
writeMemory(shmid);
//讀
else if(argv[1][0] == 'r')
readMemory(shmid);
//設定
else
testShmCtl(shmid);
return 0;