共享内存

Qt 提供了两种与同一系统中其他进程共享内存的技术:QSharedMemory 和使用QFile 的内存映射文件。与其他进程共享的内存通常被称为 "段",虽然过去在具有分段内存模型的处理器上可能是以特定段的形式实现的,但在任何现代操作系统中都不是这样。共享内存段只是操作系统确保所有参与进程都能使用的内存区域。

注意: 对于参与共享的每个进程来说,内存段所在的地址几乎总是不同的。因此,应用程序必须注意只共享与位置无关的数据,如原始 C++ 类型或此类类型的数组。

使用 QSharedMemory 共享内存

QSharedMemory 提供了一个简单的应用程序接口,用于创建给定大小的共享内存段或附加到另一个进程创建的共享内存段。此外,它还提供了一对方法,可使用内部 和 整个内存段。QSystemSemaphore lock unlock

共享内存段和系统 semaphores 在系统中通过 "key "进行全局标识,在 Qt XML 中,"key "由QNativeIpcKey 类表示。此外,根据操作系统的不同,Qt 可能支持多个不同的共享内存后端;更多信息和限制请参阅本地 IPC Keys文档。

QSharedMemory 在设计上,"共享内存 "仅用于在同一权限级别内共享内存(即不与不受信任的其他进程共享内存,如其他用户启动的进程)。对于支持该功能的后端, 将创建分段,只有具有相同权限级别的进程才能连接。QSharedMemory

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

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

这种解决方案的主要优点是独立于任何后端 API,并且更易于与非 Qt 应用程序互操作。由于QTemporaryFile 是一个QFile ,应用程序可以使用该类实现清理语义,并创建唯一的共享内存段。

要锁定共享内存段,应用程序需要部署自己的机制。一种方法是使用QLockFile 。另一种成本较低的解决方案是使用 QBasicAtomicInteger 或std::atomic ,在段本身中预先确定一个偏移量。在某些操作系统上,可以使用更高级别的锁定原语;例如,在 Linux 上,应用程序可以在传递给pthread_mutex_create() 的 mutex 属性中设置 "pshared "标志,以表明该 mutex 位于共享内存段中。

需要注意的是,操作系统可能会尝试将对共享内存的任何写入提交到永久存储中。如果文件本身是临时的,这可能是用户所希望的,也可能会影响性能。在这种情况下,应用程序应查找 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 中,应用程序可以请求操作系统避免将文件内容保存到永久存储中。通过在CreateFile Win32 函数的dwFlagsAndAttributes 参数中传递FILE_ATTRIBUTE_TEMPORARY 标志、在_open() 低级函数中传递_O_SHORT_LIVED 标志,或在fopen() C 运行时函数中包含修饰符 "T",就可以执行这一请求。

此外,还有一个标记用于通知操作系统在关闭文件的最后一个句柄时删除文件(FILE_FLAG_DELETE_ON_CLOSE_O_TEMPORARY 和 "D "修饰符),但请注意,所有试图打开文件的进程都必须同意使用或不使用该标记。如果不匹配,将可能导致共享违规和文件打开失败。

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