本地 IPC 密钥
QSharedMemory 和QSystemSemaphore 类使用称为 "键 "的全系统标识符来标识其资源。低级密钥值和密钥类型通过QNativeIpcKey 类封装在 Qt XML 中。该类还通过QNativeIpcKey::toString() 和QNativeIpcKey::fromString() 提供了与其他进程交换密钥的适当方法。
Qt XML 目前为这两个类支持三种不同的后端,它们与QNativeIpcKey::Type 枚举中的可用值相匹配。
- POSIX 实时扩展(IEEE 1003.1b、POSIX.1b)
- X/Open System Interfaces (XSI) 或 System V (SVr4),虽然现在也是 POSIX 的一部分
- 视窗基元
顾名思义,Windows 基元只适用于 Windows 操作系统,而且是默认的后端。其他两个基元通常都可在 Unix 操作系统上使用。下表概述了自 Qt 6.6 以来的典型可用性:
操作系统 | POSIX | 系统 V | Windows |
---|---|---|---|
安卓 | |||
完整性 | |||
QNX | 是 | ||
MacOS | 是 | 通常 (1) | |
其他苹果操作系统 | 是 | ||
其他 Unix 系统 | 是 | 是 | |
视窗 | 罕见 (2) | 有 |
注: 1 沙盒 macOS 应用程序(包括通过 Apple App Store 发布的所有应用程序)可能无法使用 System V 对象。
注: 2 Windows 上某些与 GCC 兼容的 C 运行时提供 POSIX 兼容的共享内存支持,但这种情况很少见。微软编译器始终不提供这种支持。
要确定给定的键类型是否受支持,应用程序应调用 QSharedMemory::isKeyTypeSupported() 和 QSystemSemaphore::isKeyTypeSupported()。
QNativeIpcKey QSharedMemory: isKeyTypeSupported() 和 QSystemSemaphore::isKeyTypeSupported() 还提供了与 Qt 应用程序兼容的支持。下文将详细介绍后端限制、字符串密钥本身的内容以及兼容性。
跨平台安全密钥格式
QNativeIpcKey::setNativeKey() 和QNativeIpcKey::nativeKey() 处理底层本地密钥,该密钥可用于本地 API 并与其他非 Qt 进程共享(API 参见下文)。这种格式通常不跨平台,因此QSharedMemory 和QSystemSemaphore 都提供了一个函数,用于将跨平台标识符字符串转换为本地密钥:这两个函数是:QSharedMemory::platformSafeKey() 和 QSystemSemaphore::platformSafeKey()。
在大多数平台上,跨平台密钥的长度与文件名的长度相同,但在苹果平台上受到严格限制,只有 30 个可用字节(如果使用 US-ASCII 范围以外的字符,请注意 UTF-8 编码)。密钥的格式也类似于文件路径组件的格式,这意味着它不应包含文件名中不允许使用的任何字符,特别是那些分隔路径组件的字符(斜线和反斜线),苹果操作系统上的沙盒应用程序除外。以下是跨平台密钥的范例:"myapp"、"org.example.myapp"、"org.example.myapp-12345"。请注意,调用者有责任防止键值过大,并确保键值包含各自平台上的合法字符。Qt 会静默截断过长的键。
苹果沙箱限制:如果应用程序在苹果操作系统的沙箱中运行,密钥必须采用非常特殊的格式:<application group identifier>/<custom identifier>
。所有通过苹果应用商店发布的应用程序都必须使用沙箱。更多信息,包括如何获取应用程序的组标识符,请参见此处和此处的Apple 文档。
本地密钥格式
本节详细介绍了支持的后端本地密钥的格式。
POSIX 实时
本地密钥类似于文件名,可以包含文件名所包含的任何字符,斜线除外。POSIX 要求密钥名称中的第一个字符必须是斜线,并且不确定是否允许使用其他斜线。在大多数操作系统上,密钥长度与文件名相同,但在苹果操作系统上,密钥长度限制为 32 个字符(包括第一个斜线和结束符空值,因此只有 30 个可用字符)。
以下是本地 POSIX 密钥的范例:"/myapp"、"/org.example.myapp"、"/org.example.myapp-12345"。
QSharedMemory::platformSafeKey() 和 QSystemSemaphore::platformSafeKey() 只需在前面加上斜线。在苹果操作系统上,它们还会将结果截断为可用大小。
Windows
Windows 键类型是 NT内核对象名称,长度可达MAX_PATH
(260) 个字符。它们看起来像相对路径(即不以反斜杠或盘符开头),但与 Windows 上的文件名不同,它们区分大小写。
以下是本地 Windows 键的良好示例:"myapp"、"org.example.myapp"、"org.example.myapp-12345"。
QSharedMemory::platformSafeKey() 和 QSystemSemaphore::platformSafeKey() 分别插入了一个前缀,以区分共享内存和系统 Semaphores。
X/Open 系统接口(XSI)/系统 V
System V 密钥采用系统中文件名的形式,因此具有与文件路径完全相同的限制。如果创建对象时该文件不存在,QSharedMemory 和QSystemSemaphore 都会创建该文件。如果禁用了自动删除功能,该文件也可以在QSharedMemory 和QSystemSemaphore 之间共享而不会发生冲突,并且可以是任何现存文件(例如,可以是进程可执行文件本身,参见QCoreApplication::applicationFilePath())。路径应为绝对路径,以避免因当前目录不同而出错。
QSharedMemory::platformSafeKey() 和 QSystemSemaphore::platformSafeKey() 总是返回绝对路径。如果输入的路径已经是绝对路径,它们将保持不变。否则,它们将在应用程序通常有权限创建文件的地方预先添加一个合适的路径。
所有权
共享内存和系统信号对象需要在使用前创建,分别通过QSharedMemory::create() 或向构造函数传递QSystemSemaphore::Create 来实现。
在 Unix 系统中,创建对象的 Qt 类将负责清理相关对象。因此,如果带有该 C++ 对象的应用程序以不干净的方式退出(崩溃、qFatal() 等),该对象可能会被遗留下来。如果发生这种情况,应用程序可能无法再次创建对象,而应附加到现有对象上。例如,对于QSharedMemory :
if (!shm.create(4096) && shm.error() == QSharedMemory::AlreadyExists) shm.attach();
重新附加到QSystemSemaphore 可能是不明智的,因为其中的令牌计数器可能处于未知状态,因此可能导致死锁。
POSIX 实时
POSIX 实时对象的所有权模式与文件相同,即它们的存在与使用它们的进程无关。Qt 无法确定对象是否仍在使用中,因此即使在这种情况下,自动删除也会将其移除,这将导致无法附加到同一对象,但不会影响现有的附加。
在 Qt 6.6 之前,除了在 QNX 上,Qt 从不清理 POSIX 实时对象。
X/Open 系统接口(XSI)/系统 V
Qt XML 类管理两种资源:密钥指向的文件和对象本身。QSharedMemory 合作管理对象:最后一个附件负责移除对象本身,然后移除密钥文件。QSystemSemaphore 将移除对象,如果且仅如果它被传递到QSystemSemaphore::Create ;此外,如果它创建了密钥文件,它也将移除该文件。
自 Qt 6.6 起,可以要求任一类不进行清理。
Windows
操作系统拥有对象,并将在对象的最后一个句柄关闭后进行清理。
与旧 Qt 应用程序的互操作性
QNativeIpcKey 类是在 Qt XML 6.6 中引入的。在此版本之前,QSharedMemory 和QSystemSemaphore 后端是在 Qt 自己构建时确定的。对于 Windows 系统,它始终是 Windows 后端。对于 Unix 系统,如果配置脚本确定 System V 后端可用,则默认使用 System V 后端。如果后端不可用,则默认使用 POSIX 后端。可以使用 Qt configure 脚本的-feature-ipc_posix
选项明确选择 POSIX 后端;如果启用了 POSIX 后端,则会定义QT_POSIX_IPC
宏。
Qt 6.6 保留了配置脚本选项,但不再控制后端的可用性。相反,它改变了QNativeIpcKey::legacyDefaultTypeForOs() 的返回值。需要保持兼容性的应用程序必须专门使用这种密钥类型,以保证互操作性。
QSharedMemory 和QSystemSemaphore 中的应用程序接口都有跨平台密钥的概念,但现在已被弃用,转而使用 QSharedMemory::legacyNativeKey() 和 QSystemSemaphore::legacyNativeKey()。这两个函数产生的本地密钥与之前版本中被弃用的函数产生的本地密钥相同。例如,如果旧代码是
QSharedMemory shm("org.example.myapplication"); QSystemSemaphore sem("org.example.myapplication");
可以更新为
QSharedMemory shm(QSharedMemory::legacyNativeKey("org.example.myapplication")); QSystemSemaphore sem(QSystemSemaphore::legacyNativeKey("org.example.myapplication"));
如果两个应用程序交换了本地密钥,就不需要更新代码,例如:legacyNativeKey()和legacyNativeKey():
QSharedMemory shm; shm.setNativeKey(key);
不过,如果旧版本的应用程序确实接受本地密钥,新版本的应用程序可以选择使用platformSafeKey()
,第二个参数为QNativeIpcKey::legacyDefaultTypeForOs() 。
X/Open 系统接口 (XSI) / 系统 V
切勿使用QSharedMemory 密钥的现有文件,因为旧 Qt XML 应用程序可能会试图删除它。相反,让QSharedMemory 来创建它。
与非 Qt 应用程序的互操作性
可以与非 Qt 应用程序互操作,但有一些限制:
- 共享内存段的创建不得竞速
- QSharedMemory 不支持锁定段
与非 Qt 应用程序的通信必须始终通过本地密钥。
QSharedMemory 非 Qt 应用程序可以选择将整个段映射到内存中。非 Qt 应用程序可以选择只将其中的一部分映射到内存中,而不会产生任何不良影响。
POSIX 实时
POSIX 共享内存可以使用shm_open()打开,POSIX 系统 semaphores 可以使用sem_open()打开。
这两个函数都使用name
参数,该参数是QNativeIpcKey::nativeKey() 的结果,并使用QFile::encodeName() /QFile::decodeName() 对文件名进行编码。
视窗
Windows 共享内存对象可以使用CreateFileMappingW打开,Windows 系统信号对象可以使用CreateSemaphoreW 打开。尽管这两个函数的名称都以 "Create "开头,但它们都可以附加到现有对象。
这些函数的lpName
参数是QNativeIpcKey::nativeKey() 的结果,未经转换。
如果外来应用程序使用这些函数的非 Unicode 版本(以 "A "结尾),则可以使用QString 将名称转换为 8 位或从 8 位转换为 8 位。
X/Open System Interfaces (XSI) / System V
System V 共享内存可使用shmget()函数获取,System V 系统 semaphores 可使用semget()函数获取。
这两个函数的key
参数都是ftok() 函数的结果,当传递从QNativeIpcKey::nativeKey() 获得的文件名时,id
为 81 或 0x51(ASCII 大写字母'Q')。
System V semaphore 对象可能包含多个 semaphores,但QSystemSemaphore 只使用第一个 semaphores(sem_num
的编号为 0)。
QSharedMemory 和QSystemSemaphore 如果是最后一个附件,默认情况下都会使用IPC_RMID
操作分别删除对象到shmctl()
和semctl()
。
© 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.