QSharedMemory
QSharedMemory
读写内存时,可以使用lock()
实现同步。因此,如果同步完成,必须使用unlock()
为共享内存区域解锁。
QSharedMemory
可以使用attach()
访问共享内存。可以通过指定参数来设置共享内存的访问模式。如果使用的是QSharedMemory::ReadOnly
模式,则只能通过只读模式访问共享内存;使用QSharedMemory::ReadWrite
模式则可以通过读写模式访问共享内存。
QSharedMemory
拥有进程并提供可以返回共享内存区域指针的成员函数。在共享内存区域,成员函数constData()
可以通过void
类型返回进程正在使用的内存区域指针。创建共享时,QSharedMemory
可以以字节为单位分配共享内存区域,还可以通过第二个参数设置函数attach()
提供的模式。
QSharedMemory
可以设置特定共享内存的固定键。函数setNativeKey()
可以设置共享内存对象的键,该函数使用从属平台的共享内存的键进行相关设置。相反,使用函数setKey()
可以设置与独立与平台的键。函数setKey()
创建与平台本地键(Native Key)映射的键。
当使用这个类时,请注意以下平台差异:
- Windows:
QSharedMemory
不“拥有”共享内存段。当所有连接到特定共享内存段的QSharedMemory
实例的线程或进程销毁了它们的QSharedMemory
实例或退出时,Windows内核会自动释放共享内存段。 - Unix:
QSharedMemory
“拥有”共享内存段。当连接到特定共享内存段的QSharedMemory
实例的最后一个线程或进程通过销毁其QSharedMemory
实例而与该段分离时,Unix内核释放该共享内存段。但是,如果最后一个线程或进程在没有运行QSharedMemory
析构函数的情况下崩溃,那么共享内存段将在崩溃时幸存下来。 - HP-UX:每个进程只允许连接一个共享内存段。这意味着在HP-UX中,
QSharedMemory
不应该跨同一进程中的多个线程使用。
示例代码
Qt提供的示例,位置: ….. \Qt5.15\Examples\Qt-5.15.2\corelib\ipc\sharedmemory
#include <QDialog>
#include <QSharedMemory>
#include "ui_dialog.h"
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = nullptr);
public slots:
void loadFromFile();
void loadFromMemory();
private:
void detach();
private:
Ui::Dialog ui;
QSharedMemory sharedMemory;
};
// 写共享内存
/*
步骤:
1.检测该进程是否连接到共享内存段,如果连接,则将该进程与共享内存分离
2.从系统足够大的内存中得到一个新的共享内存段
3.锁定该共享内存段,以阻止第二个对话框进程访问,将缓冲区中的图片复制到共享内存段
4.将共享内存段解锁,以便其他进程连接
*/
void Dialog::loadFromFile()
{
if (sharedMemory.isAttached())
if (!sharedMemory.detach())
ui.label->setText(tr("销毁共享内存失败"));
ui.label->setText(tr("选择图片"));
QString fileName = QFileDialog::getOpenFileName(0, QString(), QString(),
tr("Images (*.png *.xpm *.jpg)"));
QImage image;
if (!image.load(fileName)) {
ui.label->setText(tr("选择的文件不是图片,请重新选择.错误码为:%0")
.arg(sharedMemory.errorString()));
return;
}
ui.label->setPixmap(QPixmap::fromImage(image));
// 将数据(图片)写入到 QDataStream中
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);
out << image;
int size = buffer.size();
if (!sharedMemory.create(size)) {
ui.label->setText(tr("不能创建共享内存"));
return;
}
sharedMemory.lock();
char* to = (char*)sharedMemory.data();
const char* from = buffer.data().data();
memcpy(to, from, qMin(sharedMemory.size(), size));
sharedMemory.unlock();
}
// 读共享内存
/*
步骤:
1.将该进程与进程A创建的共享内存段绑定
2.锁定共享内存段,复制数据到缓冲区,然后写入到QImage中
3.将共享内存段解锁,然后该进程与共享内存段分离
*/
void Dialog::loadFromMemory()
{
if (!sharedMemory.attach()) {
ui.label->setText(tr("不能连接到共享内存,错误码信息为:%0")
.arg(sharedMemory.errorString()));
return;
}
// 读数据
QBuffer buffer;
QDataStream in(&buffer);
QImage image;
sharedMemory.lock();
buffer.setData((char*)sharedMemory.constData(), sharedMemory.size());
buffer.open(QBuffer::ReadOnly);
in >> image;
sharedMemory.unlock();
sharedMemory.detach();
ui.label->setPixmap(QPixmap::fromImage(image));
}
Dialog::Dialog(QWidget* parent)
: QDialog(parent)
, sharedMemory("QSharedMemoryExample")
{
ui.setupUi(this);
connect(ui.loadFromFileButton, &QPushButton::clicked,
this, &Dialog::loadFromFile);
connect(ui.loadFromSharedMemoryButton, &QPushButton::clicked,
this, &Dialog::loadFromMemory);
setWindowTitle(tr("SharedMemory Example"));
}
void Dialog::detach()
{
if (!sharedMemory.detach())
ui.label->setText(tr("Unable to detach from shared memory."));
}