共享内存
是最快的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)
分离连接到进程地址空间的共享内存, 释放共享内存
共享内存设置
<sys/shm.h>
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)
{
//根据shmid连接共享内存,获取首地址
INFO_S *pstAddr;
pstAddr=(INFO_S*)shmat(shmid,NULL,0);
INFO_S stInfo;
int pos;
while(1)
{
//读取指定位置内容
fprintf(stderr,"input read pos:");
scanf("%d",&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);
}
shmdt(pstAddr);
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] = {};
while(1)
{
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;
iRet = shmctl(shmid, IPC_STAT, &stShm);
if (iRet)
{
printf("Fail to IPC_STAT!");
continue;
}
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");
continue;
}
//修改模式
stShm.shm_perm.mode= mode;
//更新
iRet = shmctl(shmid, IPC_SET, &stShm);
if (iRet)
{
perror("Fail to IPC_SET!");
continue;
}
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");
}
return;
}
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!");
return -1;
}
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;
}
原文地址:https://www.cnblogs.com/gd-luojialin/p/9216023.html