本页内容

共享内存

Qt XML 提供了两种与同一系统中其他进程共享内存的技术:QSharedMemory 和使用QFile 的内存映射文件。与其他进程共享的内存通常被称为“段”,尽管过去在采用分段内存模型的处理器上,它可能被实现为特定的段,但在任何现代操作系统中情况并非如此。 共享内存段只是操作系统确保所有参与共享的进程均可访问的内存区域。

注意: 参与共享的每个进程中,该段在内存中的地址 几乎总是不同的。因此,应用程序必须注意仅共享位置无关的数据,例如 C++ 基本类型或此类类型的数组。

使用 QSharedMemory 共享内存

QSharedMemory 提供了一个简单的 API,用于创建指定大小的共享内存段,或挂接到由其他进程创建的共享内存段上。此外,它还提供了一对方法,用于通过内部的QSystemSemaphore 对整个段进行lock 和unlock 操作。

共享内存段和系统信号量通过“密钥”在系统中进行全局标识,在 Qt 中由QNativeIpcKey 类表示。此外,根据操作系统的不同,Qt 可能支持多种不同的内存共享后端;有关更多信息和限制,请参阅《原生 IPC 密钥》文档。

QSharedMemory 该设计仅用于在同一权限级别内共享内存(即不与不受信任的其他进程共享,例如由其他用户启动的进程)。对于支持此功能的后端,QSharedMemory 将创建仅允许具有相同权限级别的进程附加的段。

通过内存映射文件共享内存

大多数文件都可以使用QFile::map() 映射到内存中,如果未指定MapPrivateOption 选项,则对映射段的任何写入操作都将被所有映射了同一文件的其他进程察觉。无法映射到内存的文件包括位于网络共享中的远程文件或位于某些文件系统中的文件。 即使操作系统允许将远程文件映射到内存中,对该文件的 I/O 操作也可能会被缓存并延迟,从而导致无法实现真正的内存共享。

该方案的主要优势在于它不依赖任何后端 API,且与非 Qt 应用程序的互操作性更简单。由于 `QTemporaryFile ` 是一个 `QFile`,应用程序可以使用该类来实现清理语义,并创建唯一的共享内存段。

为了对共享内存段进行加锁,应用程序需要部署自己的机制。一种方法是使用 `QLockFile`。另一种成本更低的解决方案是在内存段本身预先确定的偏移量处使用 `QAtomicInteger ` 或 `std::atomic `。 某些操作系统可能提供更高层次的锁定原语;例如,在 Linux 上,应用程序可以在传递给pthread_mutex_create() 的互斥锁属性中设置“pshared”标志,以指示该互斥锁位于共享内存段中。

请注意,操作系统很可能会尝试将对共享内存的任何写入操作提交到永久存储中。这可能是预期的行为,但也可能导致性能损失——尤其是当该文件本身本应是临时文件时。 在这种情况下,应用程序应使用基于 RAM 的文件系统(例如 Linux 上的tmpfs ,参见QStorageInfo::fileSystemType()),或者向本机文件打开函数传递一个标志,以告知操作系统避免将内容写入存储设备。

可以使用基于文件的共享内存与不受信任的进程进行通信,但在这种情况下,应用程序应格外谨慎。文件可能会被截断或缩小,导致访问超出文件大小的内存的应用程序崩溃。

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

在现代 Linux 系统中,虽然/tmp 目录通常是tmpfs 的挂载点,但这并非强制要求。然而,/dev/shm 目录必须是tmpfs ,其存在目的正是为了共享内存。请注意,该目录对所有人可读写(类似于/tmp 和/var/tmp ),因此应用程序必须谨慎处理其中披露的内容。 另一种替代方案是使用 XDG 运行时目录(参见QStandardPaths::writableLocation() 和QStandardPaths::RuntimeLocation ),在使用 systemd 的 Linux 系统上,该目录是用户专属的tmpfs 。

一种更安全的解决方案是使用memfd_create(2) 创建一个“memfd”,并通过进程间通信传递文件描述符,例如QDBusUnixFileDescriptor ,或者让QProcess 的子进程继承该描述符。“memfds”还可以被设置为不可缩小,因此在与不同权限级别的进程通信时使用它们是安全的。

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

FreeBSD 同样支持memfd_create(2) ,并可采用与 Linux 相同的技术将文件描述符传递给其他进程。它默认不挂载临时文件系统。

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

在 Windows 上,应用程序可以请求操作系统避免将文件内容保存到永久存储中。此请求可通过在 Win32 函数CreateFile 的dwFlagsAndAttributes 参数中传递FILE_ATTRIBUTE_TEMPORARY 标志、在低级函数_open() 中传递_O_SHORT_LIVED 标志,或在 C 运行时函数fopen() 中包含修饰符“T”来实现。

此外,还有一种标志可告知操作系统在最后一个文件句柄关闭时删除该文件(FILE_FLAG_DELETE_ON_CLOSE 、_O_TEMPORARY 以及“D”修饰符),但请注意,所有尝试打开该文件的过程必须就是否使用此标志达成一致。若不一致,很可能会导致共享冲突并导致文件打开失败。

© 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.