Gemeinsam genutzter Speicher
Qt bietet zwei Techniken zur gemeinsamen Nutzung von Speicher mit anderen Prozessen im selben System: QSharedMemory und memory-mapped files mit QFile. Speicher, der mit anderen Prozessen geteilt wird, wird oft als "Segment" bezeichnet, und obwohl er in der Vergangenheit auf Prozessoren mit segmentierten Speichermodellen als spezifische Segmente implementiert wurde, ist dies in modernen Betriebssystemen nicht der Fall. Gemeinsam genutzte Speichersegmente sind einfach Speicherbereiche, die das Betriebssystem allen beteiligten Prozessen zur Verfügung stellt.
Hinweis: Die Adresse, an der sich das Segment im Speicher befindet, wird fast immer für jeden Prozess, der an der gemeinsamen Nutzung teilnimmt, unterschiedlich sein. Daher müssen Anwendungen darauf achten, nur positionsunabhängige Daten gemeinsam zu nutzen, wie z.B. primitive C++ Typen oder Arrays solcher Typen.
Gemeinsame Nutzung von Speicher mit QSharedMemory
QSharedMemory bietet eine einfache API, um ein gemeinsames Speichersegment einer bestimmten Größe zu erstellen oder an ein Segment anzuhängen, das von einem anderen Prozess erstellt wurde. Darüber hinaus bietet es ein Paar von Methoden, um lock und unlock das gesamte Segment, unter Verwendung eines internen QSystemSemaphore.
Gemeinsame Speichersegmente und System-Semaphoren werden im System global durch einen "Schlüssel" identifiziert, der in Qt durch die Klasse QNativeIpcKey repräsentiert wird. Zusätzlich kann Qt, abhängig vom Betriebssystem, mehrere verschiedene Backends für die gemeinsame Nutzung von Speicher unterstützen; siehe die Dokumentation Native IPC Keys für weitere Informationen und Einschränkungen.
QSharedMemory ist so konzipiert, dass Speicher nur innerhalb der gleichen Berechtigungsstufe freigegeben wird (d.h. nicht mit nicht vertrauenswürdigen anderen Prozessen, wie z.B. solchen, die von anderen Benutzern gestartet wurden). Für Backends, die dies unterstützen, erstellt QSharedMemory Segmente, so dass nur Prozesse mit der gleichen Berechtigungsstufe anhängen können.
Gemeinsame Nutzung von Speicher über speicherzugeordnete Dateien
Die meisten Dateien können mit QFile::map() im Speicher abgebildet werden, und wenn die Option MapPrivateOption nicht angegeben ist, werden alle Schreibvorgänge in das abgebildete Segment von allen anderen Prozessen, die dieselbe Datei abgebildet haben, beobachtet. Zu den Ausnahmen von Dateien, die dem Speicher zugeordnet werden können, gehören entfernte Dateien in Netzwerkfreigaben oder solche, die sich in bestimmten Dateisystemen befinden. Selbst wenn das Betriebssystem die Zuordnung von entfernten Dateien zum Speicher erlaubt, werden E/A-Operationen auf die Datei wahrscheinlich zwischengespeichert und verzögert, was eine echte gemeinsame Nutzung des Speichers unmöglich macht.
Diese Lösung hat den großen Vorteil, dass sie unabhängig von einer Backend-API ist und dass die Interoperabilität mit Nicht-Qt-Anwendungen einfacher ist. Da QTemporaryFile eine QFile ist, können Anwendungen diese Klasse verwenden, um eine Aufräum-Semantik zu erreichen und auch um eindeutige gemeinsame Speichersegmente zu erstellen.
Um das Sperren des gemeinsamen Speichersegments zu erreichen, müssen die Anwendungen ihre eigenen Mechanismen einsetzen. Eine Möglichkeit ist die Verwendung von QLockFile. Eine andere und weniger kostspielige Lösung ist die Verwendung von QBasicAtomicInteger oder std::atomic
an einem vorher festgelegten Offset im Segment selbst. Auf einigen Betriebssystemen sind möglicherweise Locking-Primitive auf höherer Ebene verfügbar; unter Linux können Anwendungen beispielsweise das Flag "pshared" im Mutex-Attribut setzen, das an pthread_mutex_create()
übergeben wird, um anzuzeigen, dass sich der Mutex in einem gemeinsamen Speichersegment befindet.
Beachten Sie, dass das Betriebssystem wahrscheinlich versuchen wird, alle Schreibvorgänge im gemeinsamen Speicher dauerhaft zu speichern. Dies kann erwünscht sein oder zu Leistungseinbußen führen, wenn die Datei selbst nur temporär sein soll. In diesem Fall sollten Anwendungen ein RAM-gestütztes Dateisystem wie tmpfs
unter Linux verwenden (siehe QStorageInfo::fileSystemType()) oder ein Flag an die native Datei-Öffnungsfunktion übergeben, um das Betriebssystem darüber zu informieren, dass der Inhalt nicht gespeichert werden soll.
Es ist möglich, dateibasierten gemeinsamen Speicher für die Kommunikation mit nicht vertrauenswürdigen Prozessen zu verwenden, wobei die Anwendung in diesem Fall große Vorsicht walten lassen sollte. Die Dateien können abgeschnitten/geschrumpft werden und Anwendungen, die auf Speicher zugreifen, der größer als die Datei ist, zum Absturz bringen.
Linux-Hinweise zu memory-mapped Dateien
Auf modernen Linux-Systemen ist das Verzeichnis /tmp
zwar häufig ein Einhängepunkt für tmpfs
, dies ist jedoch keine Voraussetzung. Das Verzeichnis /dev/shm
muss jedoch ein tmpfs
sein und dient dem Zweck der gemeinsamen Nutzung von Speicher. Beachten Sie, dass dieses Verzeichnis für die ganze Welt lesbar und beschreibbar ist (wie /tmp
und /var/tmp
), so dass Anwendungen vorsichtig mit dem Inhalt sein müssen, der dort offengelegt wird. Eine andere Alternative ist die Verwendung des XDG-Laufzeitverzeichnisses (siehe QStandardPaths::writableLocation() und QStandardPaths::RuntimeLocation), das auf Linux-Systemen mit systemd ein benutzerspezifisches tmpfs
ist.
Eine noch sicherere Lösung ist die Erstellung eines "memfd" unter Verwendung von memfd_create(2)
und die Verwendung der Kommunikation zwischen den Prozessen, um den Dateideskriptor zu übergeben, wie QDBusUnixFileDescriptor oder indem man ihn an den Kindprozess eines QProcess vererben lässt. "memfds" können auch gegen das Schrumpfen versiegelt werden, so dass sie sicher verwendet werden können, wenn sie mit Prozessen mit einer anderen Privilegstufe kommunizieren.
FreeBSD-Hinweise zu memory-mapped Dateien
FreeBSD hat auch memfd_create(2)
und kann Dateideskriptoren an andere Prozesse weitergeben, wobei es die gleichen Techniken wie Linux verwendet. Es hat standardmäßig keine temporären Dateisysteme eingehängt.
Windows-Hinweise zu memory-mapped Dateien
Unter Windows kann die Anwendung das Betriebssystem auffordern, den Inhalt der Datei nicht auf dem permanenten Speicher zu speichern. Diese Anforderung wird durch die Übergabe des Flags FILE_ATTRIBUTE_TEMPORARY
im Parameter dwFlagsAndAttributes
an die Win32-Funktion CreateFile
, des Flags _O_SHORT_LIVED
an die Low-Level-Funktion _open()
oder durch Einfügen des Modifikators "T" in die C-Laufzeitfunktion fopen()
erfüllt.
Es gibt auch ein Flag, das dem Betriebssystem mitteilt, dass die Datei gelöscht werden soll, wenn das letzte Handle darauf geschlossen wird (FILE_FLAG_DELETE_ON_CLOSE
, _O_TEMPORARY
und der Modifikator "D"), aber beachten Sie, dass alle Prozesse, die versuchen, die Datei zu öffnen, sich darauf einigen müssen, dieses Flag zu verwenden oder nicht. Eine Nichtübereinstimmung führt wahrscheinlich zu einer Verletzung der Freigabe und zum Scheitern des Öffnens der Datei.
© 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.