IPC: Gemeinsamer Speicher
Zeigt, wie Bilddaten zwischen verschiedenen Prozessen mit Hilfe des Shared Memory IPC-Mechanismus ausgetauscht werden können.
Das Shared-Memory-Beispiel zeigt, wie die Klasse QSharedMemory verwendet wird, um die Kommunikation zwischen Prozessen mit Shared Memory zu implementieren. Um das Beispiel zu erstellen, führen Sie make aus. Um das Beispiel auszuführen, starten Sie zwei Instanzen der ausführbaren Datei. Die Funktion main() erstellt eine application und eine Instanz der Dialog-Klasse unseres Beispiels. Das Dialogfeld wird angezeigt, und anschließend wird die Kontrolle auf die übliche Weise an die Anwendung übergeben.
int main(int argc, char *argv[]) { QApplication application(argc, argv); Dialog dialog; dialog.show(); return application.exec(); }
Es erscheinen zwei Instanzen der Klasse Dialog.
Die Klasse Dialog erbt von QDialog. Sie kapselt die Benutzeroberfläche und eine Instanz von QSharedMemory. Sie hat auch zwei öffentliche Slots, loadFromFile() und loadFromMemory(), die den beiden Schaltflächen des Dialogs entsprechen.
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; };
Der Konstruktor baut die Widgets der Benutzeroberfläche auf und verbindet das clicked()-Signal jedes Buttons mit der entsprechenden Slot-Funktion.
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")); }
Beachten Sie, dass "QSharedMemoryExample" an den QSharedMemory() Konstruktor übergeben wird, um als Schlüssel verwendet zu werden. Dieser wird vom System als Bezeichner des zugrunde liegenden Shared-Memory-Segments verwendet.
Klicken Sie auf die Schaltfläche Load Image From File...
in einem der Dialogfelder. Der loadFromFile()-Slot wird aufgerufen. Zunächst wird geprüft, ob dem Prozess bereits ein gemeinsames Speichersegment zugeordnet ist. Wenn ja, wird dieses Segment vom Prozess getrennt, so dass wir sicher sein können, das Beispiel korrekt zu starten.
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));
Der Benutzer wird dann aufgefordert, mit QFileDialog::getOpenFileName() eine Bilddatei auszuwählen. Die ausgewählte Datei wird in ein QImage geladen. Durch die Verwendung von QImage können wir sicherstellen, dass es sich bei der ausgewählten Datei um ein gültiges Bild handelt, und es ermöglicht uns außerdem, das Bild mit setPixmap() sofort im Dialog anzuzeigen.
Als Nächstes wird das Bild mit QDataStream in ein QBuffer gestreamt. Dadurch erhalten wir die Größe, die wir dann für create() unser gemeinsames Speichersegment verwenden. Durch das Erstellen eines gemeinsamen Speichersegments wird das Segment automatisch attaches dem Prozess zugeordnet. Durch die Verwendung von QBuffer erhalten wir einen Zeiger auf die Bilddaten, den wir dann für eine memcopy() vom QBuffer in das gemeinsame Speichersegment verwenden.
// 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(); }
Beachten Sie, dass wir lock() das gemeinsame Speichersegment vor dem Kopieren in das Segment und unlock() unmittelbar nach dem Kopieren erneut aufrufen. Dadurch wird sichergestellt, dass wir exklusiven Zugriff auf das gemeinsame Speichersegment haben, um unsere memcopy() durchzuführen. Wenn ein anderer Prozess die Segmentsperre hat, wird unser Prozess blockiert, bis die Sperre verfügbar wird.
Beachten Sie auch, dass die Funktion nicht detach() aus dem gemeinsamen Speichersegment nach memcopy() und unlock(). Erinnern Sie sich daran, dass das Betriebssystem das Segment freigibt, wenn sich der letzte Prozess von einem gemeinsam genutzten Speichersegment löst. Da dieser Prozess der einzige ist, der im Moment an das gemeinsame Speichersegment angehängt ist, würde, wenn loadFromFile() sich vom gemeinsamen Speichersegment löst, das Segment zerstört werden, bevor wir zum nächsten Schritt kommen.
Wenn die Funktion zurückkehrt und Sie die Datei qt.png ausgewählt haben, sieht Ihr erster Dialog wie folgt aus.
Klicken Sie im zweiten Dialogfeld auf die Schaltfläche Display Image From Shared Memory
. Der loadFromMemory()-Slot wird aufgerufen. Zunächst wird der Prozess attaches in das gleiche gemeinsame Speichersegment geladen, das vom ersten Prozess erstellt wurde. Dann wird das Segment locks für den exklusiven Zugriff freigegeben und ein QBuffer mit den Bilddaten im gemeinsamen Speichersegment verknüpft. Anschließend werden die Daten in ein QImage gestreamt und das Segment 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)); }
In diesem Fall beendet die Funktion detach() das Segment, da wir es nun nicht mehr verwenden. Zum Schluss wird die QImage angezeigt. Zu diesem Zeitpunkt sollten beide Dialoge das gleiche Bild anzeigen. Wenn Sie das erste Dialogfeld schließen, ruft der Dialog-Destruktor den QSharedMemory -Destruktor auf, der sich vom gemeinsamen Speichersegment trennt. Da dies der letzte Prozess ist, der von dem Segment getrennt wird, gibt das Betriebssystem nun den gemeinsamen Speicher frei.
© 2025 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.