23共享内存
Posted gd-luojialin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了23共享内存相关的知识,希望对你有一定的参考价值。
共享内存
是最快的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.. ");
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 ",stInfo.szName);
printf("age:%d ",stInfo.age);
printf("szTel:%s ",stInfo.szTel);
}
shmdt(pstAddr);
return ;
}
// shmid_ds属性
void printShmInfo(struct shmid_ds* pstShm)
{
printf("----------------- SHMID_DS ----------------- ");
printf("Key : %#x ", pstShm->shm_perm.__key);
printf("Ownner uid : %d ", pstShm->shm_perm.uid);
printf("Ownner gid : %d ", pstShm->shm_perm.gid);
printf("Creater uid: %d ", pstShm->shm_perm.cuid);
printf("Creater gid: %d ", pstShm->shm_perm.cgid);
printf("Mode : %#o ", pstShm->shm_perm.mode);
printf("Seque : %d ", pstShm->shm_perm.__seq);
printf(" ");
printf("Share memory size:%d ", (int)pstShm->shm_segsz);
printf("Last time for shmat:%d ", (int)pstShm->shm_atime);
printf("Last time for shmdt:%d ", (int)pstShm->shm_dtime);
printf("Last time for change:%d ", (int)pstShm->shm_ctime);
printf("Create share memory id:%d ", (int)pstShm->shm_cpid);
printf("last read share memory id:%d ", (int)pstShm->shm_lpid);
printf("Current process number:%d ", (int)pstShm->shm_nattch);
printf("--------------------------------------------- ");
}
//提示
void Usage()
{
printf(" stat : print share memory infomation ");
printf(" set : reset share memory mode ");
printf(" exit : exit process ");
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 ", 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). ");
continue;
}
//修改模式
stShm.shm_perm.mode= mode;
//更新
iRet = shmctl(shmid, IPC_SET, &stShm);
if (iRet)
{
perror("Fail to IPC_SET!");
continue;
}
printf("Set mode success! ");
}
//退出
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! ");
}
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] ", argv[0]);
printf(" w: write share memory ");
printf(" r : read share memory ");
printf(" c : control share memory ");
return 0;
}
char szFile[] = "123";
//创建key
key_t key = ftok(szFile, 321);
if (key==-1)
{
perror("Fail to ftok!");
return -1;
}
printf("KEY: %#x ", key);
//创建共享内存
int shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0660);
if (shmid < 0)
{
perror("fail to shmget!");
return -1;
}
printf("shmid: %d ", shmid);
//写
if (argv[1][0] == ‘w‘)
{
writeMemory(shmid);
}
//读
else if(argv[1][0] == ‘r‘)
{
readMemory(shmid);
}
//设置
else
{
testShmCtl(shmid);
}
return 0;
}
以上是关于23共享内存的主要内容,如果未能解决你的问题,请参考以下文章