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 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 系统,当
/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 还拥有
memfd_create(2)
且可以使用如 Linux 的相同技术,将文件描述符传递给其它进程。默认情况下,它不挂载临时文件系统。
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.