这个例子展示了如何使用QSharedMemory类(共享内存)进行进程间通信。
构建示例,请运行make。要运行该示例,请运行两个实例。main()函数创建一个应用程序和我们示例的Dialog类的实例。显示对话框,然后将控制以标准方式传递给应用程序。
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
Dialog dialog;
dialog.show();
return application.exec();
}
展示Dialog类的两个实例。共享内存示例的屏幕截图👇

共享内存示例的屏幕截图
Dialog类继承QDialog。它封装了用户界面和QSharedMemory实例。它还具有两个公有槽函数,分别是loadFromFile()和loadFromMemory(),它们对应于对话框上的两个按钮。
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;
};
构造函数将构建用户界面小部件,并将每个按钮的clicked()信号连接到相应的槽函数。
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"));
}
请注意,"QSharedMemoryExample"将传递给QSharedMemory()构造函数以用作键值。系统会将其用作基础共享内存段的标识符。
单击Load Image From File...按钮,会调用loadFromFile()槽函数。首先,它测试共享内存段是否已附加到该进程。如果是这样,则该段将从过程中分离出来,因此可以确保我们正确地开始执行该示例。
void Dialog::loadFromFile()
{
if (sharedMemory.isAttached())
detach();
ui.label->setText(tr("Select an image file"));
QString fileName = QFileDialog::getOpenFileName(0, QString(), QString(),
tr("Images (*.png *.xpm *.jpg)"));
QImage image;
if (!image.load(fileName)) {
ui.label->setText(tr("Selected file is not an image, please select another."));
return;
}
ui.label->setPixmap(QPixmap::fromImage(image));
然后要求用户使用QFileDialog::getOpenFileName()选择图像文件。所选文件被加载到QImage中。使用QImage可以确保所选文件是有效图像,还可以使用setPixmap()在对话框中立即显示该图像。
接下来,使用QDataStream将图像流式传输到QBuffer中。设置大小,然后我们将其用于create()我们的共享内存段。创建共享内存段会自动将该段附加到进程。在这里使用QBuffer可使我们获得指向图像数据的指针,然后将其用于从QBuffer到共享内存段的memcopy()。
// load into shared memory
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);
out << image;
int size = buffer.size();
if (!sharedMemory.create(size)) {
ui.label->setText(tr("Unable to create shared memory segment."));
return;
}
sharedMemory.lock();
char *to = (char*)sharedMemory.data();
const char *from = buffer.data().data();
memcpy(to, from, qMin(sharedMemory.size(), size));
sharedMemory.unlock();
}
请注意,在复制到共享内存段之前,我们先对其进行lock(),然后在复制后立即再次对其进行unlock()。这样可以确保我们拥有对共享内存段的独占访问权来执行我们的memcopy()。如果某个其他进程具有段锁,则我们的进程将阻塞,直到该锁可用为止。
还要注意,该函数不会在memcopy()和unlock()之后从共享内存段中detach()。回想一下,当最后一个进程从共享内存段中分离时,该段将由操作系统释放。由于此过程目前仅连接到共享内存段,因此,如果loadFromFile()从共享内存段分离,则该段将被销毁,然后再进行下一步。
函数返回时,如果您选择的文件是qt.png,则第一个对话框如下所示。

void Dialog::loadFromMemory()
{
if (!sharedMemory.attach()) {
ui.label->setText(tr("Unable to attach to shared memory segment.\n" \
"Load an image first."));
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));
}
在这种情况下,该函数会从该段执行detach(),因为现在我们已经有效地完成了对它的使用。最后,显示QImage。此时,两个对话框都应显示相同的图像。当关闭第一个对话框时,对话框析构函数调用QSharedMemory析构函数,该析构函数与共享内存段分离。由于这是要从该段分离的最后一个进程,因此操作系统现在将释放共享内存。

C:\Qt\{你的Qt版本}\Examples\{你的Qt版本}\corelib\ipc\sharedmemoryhttps://doc.qt.io/qt-5/qtcore-ipc-sharedmemory-example.html