本机 IPC (进程间通信) 键

The QSharedMemory and QSystemSemaphore 类使用称为 Key 的系统范围标识符,标识其资源。Qt 封装低级 Key 值及 Key 类型是使用 QNativeIpcKey 类。该类还提供与其它进程交换 Key 的适当手段,通过 QNativeIpcKey::toString () 和 QNativeIpcKey::fromString ().

Qt 目前支持这 2 类的 3 个截然不同后端,匹配值可用于 QNativeIpcKey::Type 枚举。

  • POSIX 实时扩展 (IEEE 1003.1b, POSIX.1b)
  • XSI (X/开放系统接口) 或 System V (SVr4),虽然现在也是 POSIX (便携式操作系统接口) 的一部分
  • Windows 原语

顾名思义,Windows 原语只可用于 Windows 操作系统,在哪里它们是默认后端。其它 2 个通常可用于 Unix 操作系统。下表提供从 Qt 6.6 起的典型可用概述:

操作系统 POSIX System V Windows
Android
INTEGRITY
QNX Yes
macOS Yes 通常 (1)
其它 Apple OS Yes
其它 Unix 系统 Yes Yes
Windows 不常 (2) Yes

注意: 1 Sandboxed macOS applications, which include all applications distributed via the Apple App Store, may not use System V objects.

注意: 2 Some GCC-compatible C runtimes on Windows provide POSIX-compatible shared memory support, but this is rare. It is always absent with the Microsoft compiler.

To determine whether a given key type is supported, applications should call QSharedMemory::isKeyTypeSupported() and QSystemSemaphore::isKeyTypeSupported().

QNativeIpcKey also provides support for compatibility with Qt applications prior to its introduction. The following sections detail the limitations of the backends, the contents of the string keys themselves, and compatibility.

跨平台安全键格式

QNativeIpcKey::setNativeKey () 和 QNativeIpcKey::nativeKey () handle the low-level native key, which may be used with the native APIs and shared with other, non-Qt processes (see below for the API). This format is not usually cross-platform, so both QSharedMemory and QSystemSemaphore provide a function to translate a cross-platform identifier string to the native key: QSharedMemory::platformSafeKey() and QSystemSemaphore::platformSafeKey().

The length of the cross-platform key on most platforms is the same as that of a file name, but is severely limited on Apple platforms to only 30 usable bytes (be mindful of UTF-8 encoding if using characters outside the US-ASCII range). The format of the key is also similar to that of a file path component, meaning it should not contain any characters not allowed in file names, in particular those that separate path components (slash and backslash), with the exception of sandboxed applications on Apple operating systems. The following are good examples of cross-platform keys: "myapp", "org.example.myapp", "org.example.myapp-12345". Note that it is up to the caller to prevent oversized keys, and to ensure that the key contains legal characters on the respective platform. Qt will silently truncate keys that are too long.

Apple 沙盒局限性: if the application is running inside of a sandbox in an Apple operating system, the key must be in a very specific format: <application group identifier>/<custom identifier> . Sandboxing is implied for all applications distributed through the Apple App Store. See Apple's documentation here and here for more information, including how to obtain the application's group identifier.

本机键格式

This section details the format of the native keys of the supported backends.

POSIX (便携式操作系统接口) 实时

Native keys resemble file names and may contain any character that file names do, except for a slash. POSIX requires the first character in the key name to be a slash and leaves undetermined whether any additional slashes are permitted. On most operating systems, the key length is the same as a file name, but it is limited to 32 characters on Apple operating systems (this includes the first slash and the terminating null, so only 30 usable characters are possible).

The following are good examples of native POSIX keys: "/myapp", "/org.example.myapp", "/org.example.myapp-12345".

QSharedMemory::platformSafeKey() and QSystemSemaphore::platformSafeKey() simply prepend the slash. On Apple operating systems, they also truncate the result to the available size.

Windows

Windows 键类型是 NT 内核对象名 且可能达到 MAX_PATH (260) 个长度字符。它们看起来像相对路径 (也就是说,它们不以 / 反斜杠或驱动器字母开头),但不像 Windows 文件名,它们区分大小写。

以下是 Windows 本地键的很好范例:myapp、org.example.myapp、org.example.myapp-12345。

QSharedMemory::platformSafeKey() 和 QSystemSemaphore::platformSafeKey() 插入前缀以分别消除共享内存和系统信号量的歧义。

X/Open System Interfaces (XSI) / System V

System V keys take the form of the name of a file in the system, and thus have the exact same limitations as file paths do. Both QSharedMemory and QSystemSemaphore will create this file if it does not exist when creating the object. If auto-removal is disabled, it may also be shared between QSharedMemory and QSystemSemaphore without conflict and can be any extant file (for example, it can be the process executable itself, see QCoreApplication::applicationFilePath ()). The path should be an absolute one to avoid mistakes due to different current directories.

QSharedMemory::platformSafeKey() and QSystemSemaphore::platformSafeKey() always return an absolute path. If the input was already absolute, they will return their input unchanged. Otherwise, they will prepend a suitable path where the application usually has permission to create files in.

所有权

Shared memory and system semaphore objects need to be created before use, which is accomplished with QSharedMemory::create () 或通过传递 QSystemSemaphore::Create to the constructor, respectively.

On Unix systems, the Qt classes that created the object will be responsible for cleaning up the object in question. Therefore, if the application with that C++ object exits uncleanly (a crash, qFatal (), etc.), the object may be left behind. If that happens, applications may fail to create the object again and should instead attach to an existing one. For example, for QSharedMemory :

if (!shm.create(4096) && shm.error() == QSharedMemory::AlreadyExists)
    shm.attach();
					

Re-attaching to a QSystemSemaphore is probably unwise, as the token counter in it is probably in an unknown state and therefore may lead to deadlocks.

POSIX (便携式操作系统接口) 实时

POSIX Realtime object ownership is patterned after files, in the sense that they exist independent of any process using them or not. Qt is unable to determine if the object is still in use, so auto-removal will remove it even then, which will make attaching to the same object impossible but otherwise not affecting existing attachments.

Prior to Qt 6.6, Qt never cleaned up POSIX Realtime objects, except on QNX.

X/Open System Interfaces (XSI) / System V

There are two resources managed by the Qt classes: the file the key refers to and the object itself. QSharedMemory manages the object cooperatively: the last attachment is responsible for removing the object itself and then removing the key file. QSystemSemaphore will remove the object if and only if it was passed QSystemSemaphore::Create ; additionally, if it created the key file, it will remove that too.

Since Qt 6.6, it is possible to ask either class not to clean up.

Windows

操作系统拥有对象,并清理对象在关闭其最后一个句柄后。

与旧 Qt 应用程序互操作

The QNativeIpcKey class was introduced in Qt 6.6. Prior to this version, QSharedMemory and QSystemSemaphore backends were determined at the time of Qt's own build. For Windows systems, it was always the Windows backend. For Unix systems, it defaulted to the System V backend if the configuration script determined it was available. If it was not available, it fell back to the POSIX one. The POSIX backend could be explicitly selected using the -feature-ipc_posix option to the Qt configure script; if it was enabled, the QT_POSIX_IPC macro would be defined.

Qt 6.6 retains the configure script option but it no longer controls the availability of the backends. Instead, it changes what QNativeIpcKey::legacyDefaultTypeForOs () will return. Applications that need to retain compatibility must use this key type exclusively to guarantee interoperability.

The API in both QSharedMemory and QSystemSemaphore had the concept of a cross-platform key, which is now deprecated in favor of using QSharedMemory::legacyNativeKey() and QSystemSemaphore::legacyNativeKey(). Those two functions produce the same native key as the deprecated functions did in prior versions. If the old code was for example:

QSharedMemory shm("org.example.myapplication");
QSystemSemaphore sem("org.example.myapplication");
					

It can be updated to be:

QSharedMemory shm(QSharedMemory::legacyNativeKey("org.example.myapplication"));
QSystemSemaphore sem(QSystemSemaphore::legacyNativeKey("org.example.myapplication"));
					

If the two applications exchanged native keys, there is no need to update code such as:

QSharedMemory shm;
shm.setNativeKey(key);
					

Though if the older application did accept a native key, the new one may opt to use platformSafeKey() with a second argument of QNativeIpcKey::legacyDefaultTypeForOs ().

X/Open System Interfaces (XSI) / System V

Never use existing files for QSharedMemory keys, as the old Qt application may attempt to remove it. Instead, let QSharedMemory create it.

与非 Qt 应用程序互操作

Interoperability with non-Qt applications is possible, with some limitations:

  • Creation of shared memory segments must not race
  • QSharedMemory support for locking the segment is unavailable

Communication with non-Qt applications must always be through the native key.

QSharedMemory always maps the entire segment to memory. The non-Qt application may choose to only map a subset of it to memory, with no ill effects.

POSIX (便携式操作系统接口) 实时

POSIX shared memory can be opened using shm_open() and POSIX system semaphores can be opened using sem_open() .

Both of those functions take a 名称 parameter that is the result of QNativeIpcKey::nativeKey (), encoded for file names using QFile::encodeName () / QFile::decodeName ().

Windows

Windows shared memory objects can be opened using CreateFileMappingW and Windows system semaphore objects can be opened using CreateSemaphoreW . Despite the name of both functions starting with "Create", they are able to attach to existing objects.

The lpName parameter to those functions is the result of QNativeIpcKey::nativeKey (), without transformation.

If the foreign application uses the non-Unicode version of those functions (ending in "A"), the name can be converted to and from 8-bit using QString .

X/Open System Interfaces (XSI) / System V

System V shared memory can be obtained using shmget() and System V system semaphores can be obtained using semget() .

The key parameter to either of those functions is the result of the ftok() function when passed the file name obtained from QNativeIpcKey::nativeKey () with an id of 81 or 0x51 (the ASCII capital letter 'Q').

System V semaphore objects may contain multiple semaphores, but QSystemSemaphore only uses the first one (number 0 for sem_num ).

Both QSharedMemory and QSystemSemaphore default to removing the object using the IPC_RMID operation to shmctl() and semctl() respectively if they are the last attachment.