共享内存(Shared Memory)是一种最为高效的进程间通信方式,进程之间可以通过共享内存进行数据通信。共享内存是一个特定的内存区域,可以被多个进程同时访问。一个进程可以将数据写入共享内存,而另一个进程可以从共享内存读取数据。大数量数据的时候使用。
本实例使用QT实现了一个进程向共享内存写数据,一个进程向共享内存读数据。
照片存放位置在Debug的Image 里
(一)ShareMemory_write向共享内存中写入照片并展示在UI界面的Label中。
widget.h头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QSharedMemory>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_Btn_in_clicked();
private:
Ui::Widget *ui;
QSharedMemory *sharememory_write=nullptr;
};
#endif // WIDGET_H
widget.cpp源文件
#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QDebug>
#include <QBuffer>
#include <QDataStream>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
sharememory_write = new QSharedMemory("kis");
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_Btn_in_clicked()
{
if(sharememory_write->isAttached())//判断程序是否关联共享内存
sharememory_write->detach();//解除关联
QString fileName = QFileDialog::getOpenFileName(this,"打开文件",QString(),tr("Image(*.jpg *.gif *.png)"));
QImage image;
if(!image.load(fileName)){
qDebug()<<"加载图片失败";
return;
}
ui->label->setPixmap(QPixmap::fromImage(image).scaled(ui->label->width(),ui->label->height()));
QByteArray pixArray;
QBuffer buffer(&pixArray);
buffer.open(QIODevice::ReadWrite);//pixmap不能为空,必须先将图片加载到pixmap中
image.save(&buffer,"png");
// qDebug()<<pixArray.size();
//创建共享内存段,失败则显示错误原因
if(!sharememory_write->create(pixArray.size()))
{
qDebug()<<"创建共享内存失败";
return;
}
sharememory_write->lock();
memcpy(sharememory_write->data(),pixArray.data(),pixArray.size());//将图片存入共享内存中
sharememory_write->unlock();
}
image.save(&buffer,"png");//注意一定要保留图片的原格式,不然我之前选的bmp格式,导出后图片背景为黑色,不是原图。
(二)ShareMemory_read读共享内存中的
widget.h头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QSharedMemory>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_Btn_out_clicked();
private:
Ui::Widget *ui;
QSharedMemory *sharememory_read=nullptr;
};
#endif // WIDGET_H
照片并展示在UI界面的Label中。
widget.cpp源文件
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
sharememory_read = new QSharedMemory("kis");
sharememory_read->attach();//将共享内存附加到当前进程的地址空间
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_Btn_out_clicked()
{
//尝试将该进程附加到共享内存段,成功返回true
if(!sharememory_read->isAttached())//判断程序是否关联共享内存
{
qDebug()<<"无法关联共享内存";
return;
}
QByteArray array;
array.resize(sharememory_read->size());
sharememory_read->lock();
//方法一将图片存入共享内存中
// memcpy(array.data(),(char *)sharememory_read->constData(),sharememory_read->size());
//方法二
memcpy(array.data(),sharememory_read->data(),sharememory_read->size());
sharememory_read->unlock();
// qDebug()<< QImage::fromData(array)<<sharememory_read->size()<<array.toHex('|');
ui->label->setPixmap(QPixmap::fromImage(QImage::fromData(array)).scaled(ui->label->width(),ui->label->height()));
sharememory_read->detach();
}
效果图如下:
我还存在疑问:
步骤上,我必须先执行ShareMemory_write,将图片导入界面了才能再运行ShareMemory_read,如果两个程序先后启动,我再点导入按钮,导入图片后,点导出没有反应。导出图片后,关闭程序ShareMemory_write,执行ShareMemory_read,打印“关联共享内存失败”。
回答:当绑定共享内存的进程都被关闭,操作系统会回收这个共享内存空间。
当一个进程写入共享内存后,关闭这个程序,共享内存的数据不在了吗?为什么另一个进程用Key来调共享内存的数据会失败,必须两个进程都打开?
回答:共享内存在ShareMemory_write的on_Btn_in_clicked()函数里被创建,当没有点击按钮前,ShareMemory_read的构建函数里不能绑定共享内存。会报“关联共享内存失败”。