共享内存
- 一.原理
- 二.创建共享内存
- 1.shmget
- 2.写一个共享内存代码
- 三.进行通信
- 1.各种接口
- 2.各接口使用代码
- 3.一次简单的通信
- 四.共享内存的特点
一.原理
直接原理
共享内存顾名思义就是共同使用的一块空间。
很明显操作系统需要对这块内存进行管理,那么就避免不了先描述后组织的策略。
二.创建共享内存
1.shmget
申请一块共享内存-shmget
第二个参数:创建共享内存的大小,单位字节。
第三个参数:多个选项
返回值:如果成功返回共享内存标识符,如果失败返回-1。
操作系统怎么保证不同进程看到同一个共享内存呢?怎么知道这块内存是否存在呢? 这就需要对第一个参数进行讨论了。
2.写一个共享内存代码
comm.hpp
#ifndef __COMM_HPP__
#define __COMM_HPP__
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
const int size=4096;
const string path="/home/chz";//任意写
const int proj_id=0x6666;//任意写
key_t Getkey()//获取一个key
{
key_t k=ftok(path.c_str(),proj_id);
if(k<0)
{
perror("Create key wrong\n");
exit(1);
}
cout<<"Create key sucess,key:"<<k<<endl;
return k;
}
int GetshareMem()//获取一个chmid
{
key_t k=Getkey();
int shmid=shmget(k,size,IPC_CREAT|IPC_EXCL|0666);//创建方式和权限
if(shmid<0)
{
perror("Create shmget wrong\n");
exit(2);
}
cout<<"Create shmget sucess,shmid;"<<shmid<<endl;
return shmid;
}
#endif
前面说过共享内存如果不主动释放会一直存在,所以在调用该函数后我们可以使用ipcs -m查看内核的进程资源。
perms是权限,nattch是与之相连的文件,byte是共享内存大小(建议一般按4096的整数倍创建,因为系统一次分配的最小内存是4KB)。
使用ipcrm -m+shmid可以手动删除。
三.进行通信
1.各种接口
将共享内存挂入
第一个参数毫无疑问是共享内存标识符。
第二个参数一般设置为NULL。因为共享内存是在物理内存上,要将其挂到虚拟内存的共享区,但具体挂到共享区哪个位置一般由操作系统决定。该函数的返回值就是具体的起始地址。
第三个参数一般设为0。它是改变挂接时的权限,虽然我们设置的共享内存权限是666,但可以通过这个参数让它只读。
取消挂入
控制共享内存
第二个参数:要进行什么操作。(有许多参数可以自行查看,这里使用 IPC_RMID删除该共享内存)
第三个参数:共享内存的属性。
2.各接口使用代码
processa.cc
#include"comm.hpp"
#include <unistd.h>
int main()
{
int shmid=GetshareMem();
sleep(3);
char*shmaddr=(char*)shmat(shmid,NULL,0);//将共享内存挂入
cout<<"挂入内存"<<endl;
sleep(3);
shdit(shmaddr);//取消挂入
cout<<"取消挂入"<<endl;
sleep(3);
shmctl(shmid,IPC_RMID,nullptr);//销毁共享内存
cout<<"销毁共享内存"<<endl;
return 0;
}
3.一次简单的通信
稍微修改一下comm.hpp,主要在shmget,当一个进程创建时,让另一个进程能获取
#ifndef __COMM_HPP__
#define __COMM_HPP__
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
const int size=4096;
const string path="/home/chz";//任意写
const int proj_id=0x6666;//任意写
key_t Getkey()//获取一个key
{
key_t k=ftok(path.c_str(),proj_id);
if(k<0)
{
perror("Create key wrong\n");
exit(1);
}
cout<<"Create key sucess,key:"<<k<<endl;
return k;
}
int GetShareMemHelper(int flag)//获取一个chmid
{
key_t k=Getkey();
int shmid=shmget(k,size,flag);//创建方式和权限
if(shmid<0)
{
perror("Create shmget wrong\n");
exit(2);
}
cout<<"Create shmget sucess,shmid;"<<shmid<<endl;
return shmid;
}
int CreateShm()
{
return GetShareMemHelper(IPC_CREAT|IPC_EXCL|0666);
}
int GetShm()
{
return GetShareMemHelper(IPC_CREAT);
}
#endif
processa.cc
#include"comm.hpp"
#include <unistd.h>
int main()
{
int shmid=CreateShm();//创建共享内存
//挂入内存
//获取起始地址,并把它当作字符串使用
char*shmaddr=(char*)shmat(shmid,nullptr,0);
while(true)
{
//直接读取
cout<<"I am read:";
cout<<shmaddr<<endl;
sleep(1);
}
shmdt(shmaddr);//取消挂起
shmctl(shmid,IPC_RMID,nullptr);
return 0;
}
processb.cc
#include"comm.hpp"
int main()
{
int shmid=GetShm();//获取共享内存
//挂入内存
//获取起始地址,并把它当作字符串使用
char*shmaddr=(char*)shmat(shmid,nullptr,0);
while(true)
{
cout<<"please Enter:";
fgets(shmaddr,4096,stdin);//直接从键盘读入
}
return 0;
}
makefile
.PHONY:all
all:processa processb
processa:processa.cc
g++ -o $@ $^ -std=c++11
processb:processb.cc
g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
rm -f processa processb
四.共享内存的特点
1.共享内存没有同步互斥之类的保护机制。(即使没有写入也依然会读)
2.共享内存是所有的进程通信中最快的。(拷贝少)
3.共享内存里的所有数据由用户自己维护。(操作系统不会自动将数据清零)