共享内存让不同进程看到同一份资源的方式就是,在物理内存当中申请一块内存空间,然后将这块内存空间分别与各个进程各自的页表之间建立映射,再在虚拟地址空间当中开辟空间并将虚拟地址填充到各自页表的对应位置,使得虚拟地址和物理地址之间建立起对应关系,至此这些进程便看到了同一份物理内存,这块物理内存就叫做共享内存。
共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据
创建共享内存
int shmget(key_t key, size_t size, int shmflg);
key:这个共享内存段名字
size:共享内存大小
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1
如何创建key呢?
key_t ftok(const char *pathname, int proj_id);
pathname:共享内存的路径
proj_id:根据路径和id值生成key值
shmflg说明
IPC_CREAT:如果内核中不存在键值与key相等的共享内存,则新建一个共享内存并返回该共享内存的标识码;如果存在这样的共享内存,则直接返回该共享内存的标识码
IPC_CREAT | IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个共享内存并返回该共享内存的标识码;如果存在这样的共享内存,则出错返回
删除共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构 返回值:成功返回0;失败返回-1
cmd说明
命令 | 说明 |
---|---|
IPC_STAT | 把buf中的数据设置为共享内存的当期关联值 |
IPC_SET | 在进程有足够权限的前提下,将共享内存的当前关联值设置为buf所指的数据结构中的值 |
IPC_RMID | 删除共享内存段 |
将共享内存段连接到进程地址空间
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid: 共享内存标识
shmaddr:指定连接的地址
shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1
将共享内存段与当前进程脱离
int shmdt(const void *shmaddr);
shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
//comm.hpp
#include
#include
#include
#include
#include
using namespace std;
#define PATH_IPC "/home/zjq/linuxl"
#define PROJ_ID 0x114
#define MAX_SIZE 4096
key_t CreatKey()
{
key_t ret = ftok(PATH_IPC,PROJ_ID);
return ret;
}
//IpcShmCli.cpp
#include"comm.hpp"
int main()
{
key_t key = CreatKey();
//创建共享内存
int shmid = shmget(key,MAX_SIZE,IPC_CREAT | 0666);
if(shmid<0)
{
cout<<"创建共享内存失败\n";
return 1;
}
cout<<"客户端:创建共享内存成功"<<endl;
//关联
char* str = (char*)shmat(shmid,nullptr,0);
if(str==nullptr)
{
cout<<"关联失败"<<endl;
}
cout<<"关联成功"<<endl;
//使用
for(int i=0;i<26;i++)
{
sleep(1);
str[i]='A'+i;
str[i+1]='\0';
}
//去关联
shmdt(str);
return 0;
}
//IpcShmSer.cpp
#include"comm.hpp"
int main()
{
key_t key = CreatKey();
//创建共享内存
int shmid = shmget(key,MAX_SIZE,IPC_CREAT | IPC_EXCL | 0666);
if(shmid<0)
{
cout<<"创建共享内存失败\n";
return 1;
}
cout<<"服务器:创建共享内存成功"<<endl;
char* str = (char*)shmat(shmid,nullptr,0);
if(str==nullptr)
{
cout<<"关联失败"<<endl;
}
cout<<"关联成功"<<endl;
//使用
while(1)
{
sleep(1);
cout<<str<<endl;
}
//去关联
shmdt(str);
//删除共享内存
shmctl(shmid,IPC_RMID,nullptr);
return 0;
}
效果:
查看
ipcs -m
名称 | 含义 |
---|---|
key | 系统标识各个共享内存 |
shmid | 用户标识各个共享内存 |
owner | 共享内存的所有者 |
perms | 共享内存的权限 |
bytes | 共享内存的大小 |
nattch | 关联共享内存的进程数 |
status | 共享内存的状态 |
删除
ipcrm -m shmid