1.原理
多个进程申请同一块内存区域,然后使用这个内存区域来通信
查看共享内存
ipcs -m
删除共享内存
ipcrm -m 共享内存的ID号
2.相关的接口函数
(1)申请共享内存
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
返回值:成功 返回共享内存的ID号
失败 -1
参数:key --》键值,用来帮助你申请共享内存(键值相同,申请的内存区域就是一样)
键值的来源:
第一种:程序员可以自己随便写个无符号的整数
第二种:调用linux提供的ftok()函数产生键值
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
原理:该函数源码中有一套算法,根据你传递的路径名和整数计算得到一个唯一的键值
返回值:成功 返回计算得到的键值
参数:pathname --》合法的路径名
proj_id --》随便写个整数
ftok("/", 453);
size --》你要申请的内存大小,一般写成512字节的整数倍
shmflg --》IPC_CREAT //新建
IPC_EXCL //如果之前已经申请过同样的共享内存,再次申请就失败
//O_CREAT和O_EXCL类似
注意:
写法一:shmget(54552,1024,IPC_CREAT|IPC_EXCL|0777);
适用于共享内存没有申请过,第一次申请
写法二:shmget(54552,1024,0777);
适用于共享内存申请过,现在只是把共享内存打开
(2)映射得到共享内存的首地址
void *shmat(int shmid, const void *shmaddr, int shmflg);
返回值:成功 返回共享内存的首地址
失败 NULL
参数:shmid --》共享内存的ID号
shmaddr --》设置为NULL,让操作系统来给我分配首地址
shmflg --》默认设置为0
(3)解除映射
int shmdt(const void *shmaddr);
参数:shmaddr --》共享内存的首地址
(4)多功能函数,删除/设置/获取共享内存的属性信息
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:shmid --》共享内存的ID号
cmd --》IPC_STAT 获取共享内存的属性信息
IPC_SET 设置共享内存的属性信息
IPC_RMID 删除共享内存
buf --》保存共享内存的属性信息
struct shmid_ds
{
struct ipc_perm shm_perm; //权限
shm_segsz; //大小
}
struct ipc_perm
{
__key; //键值
mode; //权限
}
共享内存的属性:大小,ID号,键值等等这些
获取共享内存的属性信息
#include "myhead.h"
int main()
{
int shmid;
//申请共享内存
shmid=shmget(54552,1024,IPC_CREAT|IPC_EXCL|0777);
if(shmid==-1) //发生错误
{
//依据刚才讲解的错误码原理,进一步分析产生错误的原因
if(errno==EEXIST) //说明错误的原因是共享内存已经存在
{
shmid=shmget(54552,1024,0777); //打开共享内存
}
else //说明错误是其他类型的错误
{
perror("申请共享内存失败了!\n");
return -1;
}
}
struct shmid_ds myds;
//获取刚才你申请的共享内存的属性信息
shmctl(shmid,IPC_STAT,&myds);
//打印你获得的属性信息
printf("共享内存的大小是:%ld\n",myds.shm_segsz);
printf("共享内存的键值是:%ld\n",myds.shm_perm.__key);
printf("共享内存的权限是:%o\n",myds.shm_perm.mode);
//映射得到共享内存的首地址
char *p=shmat(shmid,NULL,0);
//p指向的就是你刚才申请得到的1024字节的内存首地址
if(p==NULL)
{
perror("映射共享内存失败!\n");
return -1;
}
//解除映射
shmdt(p);
return 0;
}
设置共享内存的属性信息
#include "myhead.h"
int main()
{
int shmid;
//申请共享内存
shmid=shmget(54552,1024,IPC_CREAT|IPC_EXCL|0777);
if(shmid==-1) //发生错误
{
//依据刚才讲解的错误码原理,进一步分析产生错误的原因
if(errno==EEXIST) //说明错误的原因是共享内存已经存在
{
shmid=shmget(54552,1024,0777); //打开共享内存
}
else //说明错误是其他类型的错误
{
perror("申请共享内存失败了!\n");
return -1;
}
}
struct shmid_ds myds;
bzero(&myds,sizeof(myds));
//初始化
myds.shm_perm.mode=0666;
//设置共享内存的属性信息
shmctl(shmid,IPC_SET,&myds);
//映射得到共享内存的首地址
char *p=shmat(shmid,NULL,0);
//p指向的就是你刚才申请得到的1024字节的内存首地址
if(p==NULL)
{
perror("映射共享内存失败!\n");
return -1;
}
//解除映射
shmdt(p);
return 0;
}
删除共享内存
#include "myhead.h"
int main()
{
int shmid;
//申请共享内存
shmid=shmget(54552,1024,IPC_CREAT|IPC_EXCL|0777);
if(shmid==-1) //发生错误
{
//依据刚才讲解的错误码原理,进一步分析产生错误的原因
if(errno==EEXIST) //说明错误的原因是共享内存已经存在
{
shmid=shmget(54552,1024,0777); //打开共享内存
}
else //说明错误是其他类型的错误
{
perror("申请共享内存失败了!\n");
return -1;
}
}
//映射得到共享内存的首地址
char *p=shmat(shmid,NULL,0);
//p指向的就是你刚才申请得到的1024字节的内存首地址
if(p==NULL)
{
perror("映射共享内存失败!\n");
return -1;
}
//解除映射
shmdt(p);
//删除共享内存
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
进程之间利用共享内存单向通讯
#include "myhead.h"
int main()
{
int shmid;
//申请共享内存
shmid=shmget(ftok("/home/gec",10),1024,IPC_CREAT|IPC_EXCL|0777);
if(shmid==-1) //发生错误
{
//依据刚才讲解的错误码原理,进一步分析产生错误的原因
if(errno==EEXIST) //说明错误的原因是共享内存已经存在
{
shmid=shmget(ftok("/home/gec",10),1024,0777); //打开共享内存
}
else //说明错误是其他类型的错误
{
perror("申请共享内存失败了!\n");
return -1;
}
}
//映射得到共享内存的首地址
char *p=shmat(shmid,NULL,0);
//p指向的就是你刚才申请得到的1024字节的内存首地址
if(p==NULL)
{
perror("映射共享内存失败!\n");
return -1;
}
//p1通过共享内存发送信息给p2
while(1)
{
printf("请输入要发送给p2的信息!\n");
scanf("%s",p);
}
}
#include "myhead.h"
// p2的代码
int main()
{
int shmid;
//申请共享内存
shmid=shmget(ftok("/home/gec",10),1024,IPC_CREAT|IPC_EXCL|0777);
if(shmid==-1) //发生错误
{
//依据刚才讲解的错误码原理,进一步分析产生错误的原因
if(errno==EEXIST) //说明错误的原因是共享内存已经存在
{
shmid=shmget(ftok("/home/gec",10),1024,0777); //打开共享内存
}
else //说明错误是其他类型的错误
{
perror("申请共享内存失败了!\n");
return -1;
}
}
//映射得到共享内存的首地址
char *p=shmat(shmid,NULL,0);
//p指向的就是你刚才申请得到的1024字节的内存首地址
if(p==NULL)
{
perror("映射共享内存失败!\n");
return -1;
}
//从共享内存去访问p1存放的信息
while(1)
{
if(strlen(p)!=0)
{
printf("p1发送的信息是:%s\n",p);
bzero(p,1024);
}
}
}