共享内存

Qt 提供了在同一系统中与其它进程共享内存的 2 种技术: QSharedMemory 和内存映射文件使用 QFile . Memory that is shared with other processes is often referred to as a "segment", and although it may have been implemented as specific segments on processors with segmented memory models in the past, this is not the case in any modern operating system. Shared memory segments are simply regions of memory that the operating system will ensure are available to all processes participating.

注意: The address at which the segment is located in memory will almost always be different for each process that is participating in the sharing. Therefore, applications must take care to share only position-independent data, such as primitive C++ types or arrays of such types.

使用 QSharedMemory 共享内存

QSharedMemory provides a simple API to create a shared memory segment of a given size or attach to one that was created by another process. Additionally, it provides a pair of methods to lock and unlock the whole segment, using an internal QSystemSemaphore .

Shared memory segments and system semaphores are globally identified in the system through a "key", which in Qt is represented by the QNativeIpcKey class. Additionally, depending on the OS, Qt may support multiple different backends for sharing memory; see the 本机 IPC (进程间通信) 键 documentation for more information and limitations.

QSharedMemory is designed to share memory only within the same privilege level (that is, not with untrusted other processes, such as those started by other users). For backends that support it, QSharedMemory will create segments such that only processes with the same privilege level can attach.

凭借内存映射文件共享内存

可以将大多数文件映射到内存使用 QFile::map (),和若 MapPrivateOption option is not specified, any writes to the mapped segment will be observed by all other processes that have mapped the same file. Exceptions to files that can be mapped to memory include remote files found in network shares or those located in certain filesystems. Even if the operating system does allow mapping remote files to memory, I/O operations on the file will likely be cached and delayed, thus making true memory sharing impossible.

This solution has the major advantages of being independent of any backend API and of being simpler to interoperate with from non-Qt applications. Since QTemporaryFile QFile , applications can use that class to achieve clean-up semantics and to create unique shared memory segments too.

To achieve locking of the shared memory segment, applications will need to deploy their own mechanisms. One way may be to use QLockFile . Another and less costly solution is to use QBasicAtomicInteger or std::atomic in a pre-determined offset in the segment itself. Higher-level locking primitives may be available on some operating systems; for example, on Linux, applications can set the "pshared" flag in the mutex attribute passed to pthread_mutex_create() to indicate that the mutex resides in a shared memory segment.

Be aware that the operating system will likely attempt to commit to permanent storage any writes made to the shared memory. This may be desired or it may be a performance penalty if the file itself was meant to be temporary. In that case, applications should locate a RAM-backed filesystem, such as tmpfs 在 Linux (见 QStorageInfo::fileSystemType ()), or pass a flag to the native file-opening function to inform the OS to avoid committing the contents to storage.

It is possible to use file-backed shared memory to communicate with untrusted processes, in which case the application should exercise great care. The files may be truncated/shrunk and cause applications accessing memory beyond the file's size to crash.

有关内存映射文件的 Linux 提示

在现代 Linux 系统,当 /tmp directory is often a tmpfs mount point, that is not a requirement. However, the /dev/shm directory is required to be a tmpfs and exists for the very purpose of sharing memory. Do note that it is world-readable and writable (like /tmp and /var/tmp ), so applications must be careful of the contents revealed there. Another alternative is to use the XDG Runtime Directory (see QStandardPaths::writableLocation () 和 QStandardPaths::RuntimeLocation ), which on Linux systems using systemd is a user-specific tmpfs .

An even more secure solution is to create a "memfd" using memfd_create(2) and use interprocess communication to pass the file descriptor, like QDBusUnixFileDescriptor or by letting the child process of a QProcess inherit it. "memfds" can also be sealed against being shrunk, so they are safe to be used when communicating with processes with a different privilege level.

有关内存映射文件的 FreeBSD 提示

FreeBSD 还拥有 memfd_create(2) 且可以使用如 Linux 的相同技术,将文件描述符传递给其它进程。默认情况下,它不挂载临时文件系统。

有关内存映射文件的 Windows 提示

On Windows, the application can request the operating system avoid saving the file's contents on permanent storage. This request is performed by passing the FILE_ATTRIBUTE_TEMPORARY flag in the dwFlagsAndAttributes parameter to the CreateFile Win32 function, the _O_SHORT_LIVED flag to _open() low-level function, or by including the modifier "T" to the fopen() C 运行时函数。

There's also a flag to inform the operating system to delete the file when the last handle to it is closed ( FILE_FLAG_DELETE_ON_CLOSE , _O_TEMPORARY , and the "D" modifier), but do note that all processes attempting to open the file must agree on using this flag or not using it. A mismatch will likely cause a sharing violation and failure to open the file.