【Linux:共享内存】
共享内存的概念:
- 操作系统通过页表将共享内存的起始虚拟地址映射到当前进程的地址空间中
- 共享内存是由需要通信的双方进程之一来创建
- 但该资源并不属于创建它的进程,而属于操作系统
- 共享内存可以在系统中存在多份,供不同个数,不同进程进行通信
- 因此共享内存一定会存在一个数据结构来对共享内存进行管理
- 共享内存=内存空间(数据)+共享内存的属性
共享内存的相关接口:
- key:由用户形成,具有唯一性(内核区分shm的唯一性的),内核使用的一个字段,用户不能用Key来进行shm的管理
- size:共享内存的大小
- shmflg:标记位,可以用位图传参,认识它中的两个宏:IPC_CREAT和IPC_EXCL
- IPC_CREAT:创建的共享内存不存在就创建,存在则获取该共享内存并返回
- IPC_CREAT|IPC_EXCL:创建的共享内存不存在就创建,存在则出错返回
- IPC_EXCL:单独使用没有意义
共享内存不随着进程的结束就释放,因为共享内存不属于进程而属于操作系统,需要手动释放或者后续其它系统调用。共享内存的生命周期随内核。
查共享内存的命令:
ipcs -m
删除共享内存的命令:
ipcrm -m shmid
共享内存测试代码:
#ifndef __SHM_HPP__
#define __SHM_HPP__
#include <iostream>
#include <cerrno>
#include <cstdio>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
const std::string pathname = "/home/dl/pipe/shm";
int proj_id = 0x66;
const int Creater = 1;
const int User = 2;
const int CreatShmsize=4096;
class shm
{
private:
// 获取共享内存
int GetShmhelper(key_t key, int size, int flag)
{
int shmid = shmget(key, size, flag);
if (shmid < 0)
{
perror("shmget");
}
return shmid;
}
//获取Key
key_t GetcommKey()
{
key_t k = ftok(_pathname.c_str(), _proj_id);
if (k < 0)
{
perror("ftok");
}
return k;
}
private:
key_t _key;
int _shmid;
std::string _pathname;
int _proj_id;
int _who;
public:
shm(const std::string &pathname, int proj_id, int who)
: _pathname(pathname),
_proj_id(proj_id),
_who(who)
{
_key=GetcommKey();//获取共享内存都需要该参数,因此直接在构造时生成即可
std::cout<<"shmid:"<<_shmid<<std::endl;
std::cout<<"key:"<<TOHex(_key)<<std::endl;
std::cout<<"who:"<<_who<<std::endl;
}
~shm()
{
if(_who==Creater)
{
int res=shmctl(_shmid,IPC_RMID,nullptr);
std::cout<<"shm remove done"<<std::endl;
}
}
std::string TOHex(key_t key)
{
char buffer[128];
snprintf(buffer, sizeof(buffer), "0x%x", key);
return buffer;
}
bool GetShmCreater()
{
//判断是否为创建者
if(_who==Creater)
{
int shmid = GetShmhelper(_key,CreatShmsize,IPC_CREAT|IPC_EXCL);
if(shmid>0)
std::cout<<"shm creat done"<<std::endl;
sleep(5);
return true;
}
return false;
}
bool GetShmUse()
{
//判断是否为使用者
if(_who==User)
{
int shmid = GetShmhelper(_key,CreatShmsize,IPC_CREAT);
if(shmid>0)
std::cout<<"shm get done"<<std::endl;
return true;
}
return false;
}
};
#endif