IPC:共享内存
演示如何使用共享内存 IPC 机制在不同进程之间共享图像数据。
“共享内存”示例展示了如何使用QSharedMemory 类通过共享内存实现进程间通信。要编译该示例,请运行make。要运行该示例,请启动两个可执行文件的实例。main()函数会创建一个application 以及本示例中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(QNativeIpcKey(u"QSharedMemoryExample"_s))
{
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()` 初始化共享内存段。创建共享内存段会自动将该段attaches 到进程中。在此处使用 `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)) {
if (sharedMemory.error() == QSharedMemory::AlreadyExists) {
sharedMemory.attach();
} else {
ui.label->setText(tr("Unable to create or attach to shared memory segment: %1")
.arg(sharedMemory.errorString()));
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,则第一个对话框将如下所示。

在第二个对话框中,点击“Display Image From Shared Memory ”按钮。此时将调用 loadFromMemory() 槽函数。它首先通过 `attaches ` 将进程连接到由第一个进程创建的同一共享内存段。然后,它通过 `locks ` 获取该段的独占访问权限,并将一个 `QBuffer ` 链接到共享内存段中的图像数据。接着,它将数据流式传输到 `QImage `,并执行 `unlocks ` 释放该段。
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 。此时,两个对话框都应显示同一张图像。当关闭第一个对话框时,Dialog的析构函数会调用QSharedMemory 的析构函数,从而将其从共享内存段中断开。由于这是最后一个从该段断开的进程,操作系统将释放该共享内存。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.