shmget
int shmget(key_t key, size_t size, int shmflg); //创建或打开
shmat
:将共享内存段连接到进程地址空间[说明1] shmget创建/打开共享内存后,必须使用shmat将该共享内存连接到进程的地址空间,以便进程使用。不适用shmat,进程无法使用该共享内存。
[说明2] 每个进程shmat同一个内存段后得到的地址不一样–它们都属于自己的共享内存地址)
函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
返回值
失败:返回-1;
成功:返回一个指针p(指向共享内存的第一个字节),使用p操控共享内存。
shmat使用
p=shmat(shm_id,NULL,0);//让本进程链接到共享内存会得到一个共享内存的首地址p,可以直接通过指针p去操控共享内存。
参数
shmaddr:指定连接的地址
shmflg:两个可能取值SHM_RND和SHM_RDONLY
shmaddr和shmflg的组合关系 | 共享内存最终地址 |
---|---|
shmaddr为NULL,不管shmflg | 核心自动选择一个地址 |
shmaddr不为NULL且shmflg无SHM_RND标记 | 以shmaddr为连接地址 |
shmaddr不为NULL且shmflg设置了SHM_RND标记 | 连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA) |
shmflg=SHM_RDONLY | 表示连接操作用来只读共享内存 |
shmdt
:将共享内存段与当前进程脱离int shmdt(const void *shmaddr);
参数shmaddr: 由shmat所返回的指针
注意:将共享内存段与当前进程脱离不等于删除共享内存段
shmctl
:控制共享内存int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数cmd: - IPC_STAT:获取shmid_ds结构中的值 ; - IPC_SET:设置shmid_ds结构中的值 ; - IPC_RMID:删除共享内存
其中 IPC_RMID:共享内存的删除[难点]
结论:是否能直接删除共享内存?
——>关键是看在删除以后有无进程链接到该块内存<==>等同于shmctl+shmdt删除之前有多少进程已经执行了shmat。
子进程向shm中写数据;父进程从shm中读取子进程向shm写入的数据
typedef struct student{
int age;
char name[10];
}student;
int main()
{
key_t key=ftok("/home/gjw/tmp",'a');
int shm_id=shmget(key,sizeof(int)*100,0664|IPC_CREAT);
pid_t pid=fork();
if(pid>0)
{
}
else if(pid==0)
{
void* ptr=shmat(shm_id,NULL,0);
struct student* stu=(struct student*)ptr;
stu->age=24;
strcpy(stu->name,"guojiawei");
shmdt(ptr);
exit(0);
}
sleep(1);
wait(NULL);
void* ptr=shmat(shm_id,NULL,0);
printf("age=%d, name=%s\n",((student*)ptr)->age,((student*)ptr)->name);
shmdt(ptr);
return 0;
}
共享内存模块代码的封装
头文件myipc_shm.h
#ifndef __MYIPC_SHM_H__
#define __MYIPC_SHM_H__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
int IPC_CreatShm(char *shmseedfile, int shmsize, int *shmhdl);
int IPC_MapShm(int shmhdl,void **mapaddr);
int IPC_UnMapShm(void *unmapaddr);
int IPC_DelShm(int shmhdl);
#ifdef __cplusplus
}
#endif
#endif
实现文件myipc_shm.c
#include "myipc_shm.h"
int shmflag = 0;
int shmkey;
/***********************************************************************
功能描述: 创建共享内存
参数说明: shmname [in] 是共享内存名,系统中唯一标志
shmsize [in] 是要创建的共享内存的大小;
shmhdl [out] 共享内存的句柄.
返回值: 返回0函数执行成功;非0返回错误码
************************************************************************/
int IPC_CreatShm(char *shmseedfile, int shmsize, int *shmhdl)
{
if(shmflag == 0) //判断接口中共享内存key是否已经存在
{
shmkey = ftok(shmseedfile, 'c');
if (shmkey == -1)
{
perror("ftok");
return -1;
}
shmflag = 1;
}
//创建共享内存
*shmhdl = shmget(shmkey,shmsize,IPC_CREAT|0666);
if (*shmhdl == -1) //创建失败
return -2;
return 0;
}
/***********************************************************************
功能描述: 关联共享内存
参数说明: shmhdl [in] 共享的句柄
mapaddr [out] 共享内存首地址
返回值: 返回0函数执行成功;非0返回错误码
************************************************************************/
int
IPC_MapShm(int shmhdl, void **mapaddr)
{
void *tempptr = NULL;
//连接共享内存
tempptr = (void *)shmat(shmhdl,0,SHM_RND);
if (tempptr == (void*)-1) //共享内存连接失败
return -1;
*mapaddr = tempptr; //导出共享内存首指针
return 0;
}
/***********************************************************************
功能描述: 取消共享内存关联
参数说明: unmapaddr [in] 共享内存首地址
返回值: 返回0函数执行成功;非0返回错误码
************************************************************************/
int IPC_UnMapShm(void *unmapaddr)
{
int rv;
//取消连接共享内存
rv = shmdt((char *)unmapaddr);
if (rv == -1) //取消连接失败
return -1;
return 0;
}
/***********************************************************************
功能描述: 删除共享内存
参数说明: shmhdl [in] 共享的句柄
返回值: 返回0函数执行成功;非0返回错误码
************************************************************************/
int IPC_DelShm(int shmhdl)
{
int rv;
//删除共享内存
rv = shmctl(shmhdl,IPC_RMID,NULL);
if(rv < 0) //删除共享内存失败
return -1;
return 0;
}