首先介绍下什么是共享内存。
定义:
共享内存指 (shared memory)在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据。共享内存是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。
应用场景:
1、进程间通信。
两个进程同时挂载一片共享内存,进程A写、进程B读,就达到了通信效果,这种方案的好处是,读写都是基于内存操作,效率非常之高。
2、数据共享。
类似于读写锁中的读锁原理。这里是一个进程写了后,其它多个相同的进程进行读取这片数据。比如A进程写数据到共享内存,B、C进程从共享内存读取这片数据。
3、单进程数据缓存。
比如单机上只有一个实例,该实例需要在启动的时候加载一大块资源到内存,那么,如果基于共享内存,将资源加载到共享内存,那么,下次启动的时候,只要version或者crc没变,就可以直接挂载使用,无需再次读入。比如程序启动需要加载cpu型号、内存信息、系统属性、配置文件数据等等时,软件第一次启动时先将数据加载到共享内存,后面启动时只需要从共享内存读取数据,提升程序的启动速度。
4、保证软件不重复启动。
通过共享内存绑定程序,再次启动这个程序时,进行判断该共享内存是否被绑定,是否还能够再次创建成功,来防止软件重复启动。
这里只展示场景1、2、4的代码示例。
场景1和场景2:
进程A写共享内存。
m_shareMemory.setKey("shared momery");
if(m_shareMemory.isAttached())
m_shareMemory.detach();//将该进程与共享内存段分离
QBuffer buffer; //创建缓冲区绑定数据流,然后通过数据流写数据,这样能保证数据的格协议式和编码格式不被干扰。
QDataStream in(&buffer);
buffer.open(QBuffer::ReadWrite);
in<<“test data”;
int size = buffer.size();
if(!m_shareMemory.create(size))
{
qDebug()<<"can't create memory segment"<<m_shareMemory.error();
}
m_shareMemory.lock();
char *to = (char*)m_shareMemory.data();
const char *from = (char*)buffer.data().data();
memcpy(to,from,qMin(size,m_shareMemory.size()));//数据从该进程中拷贝到共享数据内存中
m_shareMemory.unlock();//共享内层解锁
m_shareMemory.detach();
}
进程B读共享内存
m_shareMemory.setKey("shared momery");
if(!m_shareMemory.attach())//将shareMemory与该进程绑定使之可以访问shareMemory里的内容
{
qDebug()<<tr("can't attach share memory");
m_shareMemory.detach();//将shareMemeory与该进程分离
}
if (m_shareMemory.isAttached())
{
QByteArray data;
QBuffer buffer; /创建缓冲区绑定数据流,同样通过数据流读数据。这里buffer可以不通过数据流拿数据,但是这样会造成数据的格式变化。
QDataStream out(&buffer);
m_shareMemory.lock();//给shareMemory加锁
buffer.setData((char*)m_shareMemory.constData(),m_shareMemory.size());//将shareMemeory里的数据放到buffer里
buffer.open(QBuffer::ReadWrite);
out>>data;
qDebug()<<data;
m_shareMemory.unlock();//将shareMemory解锁
m_shareMemory.detach();
}
进程C读数据
#include "widget.h"
#include "ui_widget.h"
#include <QBuffer>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
startTimer(1000);
m_shareMemory.setKey("shared momery");
if (!m_shareMemory.attach())
{
qDebug()<<"attach is failed ";
m_shareMemory.detach();
}
}
Widget::~Widget()
{
delete ui;
}
void Widget::timerEvent(QTimerEvent *event)
{
QByteArray array;
QBuffer buffer;
QDataStream out(&buffer);
m_shareMemory.lock();
buffer.setData((char*)m_shareMemory.constData(),m_shareMemory.size());
buffer.open(QBuffer::ReadWrite);
out>>array;
qDebug()<<array;
m_shareMemory.unlock();
}
场景4:代码介绍