共享内存
- 一.原理
- 二.创建共享内存
- 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 processbprocessa:processa.ccg++ -o $@ $^ -std=c++11
processb:processb.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f processa processb
四.共享内存的特点
1.共享内存没有同步互斥之类的保护机制。(即使没有写入也依然会读)
2.共享内存是所有的进程通信中最快的。(拷贝少)
3.共享内存里的所有数据由用户自己维护。(操作系统不会自动将数据清零)