The QSharedMemory and QSystemSemaphore 类使用称为 Key 的系统范围标识符,标识其资源。Qt 封装低级 Key 值及 Key 类型是使用 QNativeIpcKey 类。该类还提供与其它进程交换 Key 的适当手段,通过 QNativeIpcKey::toString () 和 QNativeIpcKey::fromString ().
Qt 目前支持这 2 类的 3 个截然不同后端,匹配值可用于 QNativeIpcKey::Type 枚举。
顾名思义,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.
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 键类型是 NT
内核对象名
且可能达到
MAX_PATH
(260) 个长度字符。它们看起来像相对路径 (也就是说,它们不以 / 反斜杠或驱动器字母开头),但不像 Windows 文件名,它们区分大小写。
以下是 Windows 本地键的很好范例:myapp、org.example.myapp、org.example.myapp-12345。
QSharedMemory::platformSafeKey() 和 QSystemSemaphore::platformSafeKey() 插入前缀以分别消除共享内存和系统信号量的歧义。
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 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.
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.
操作系统拥有对象,并清理对象在关闭其最后一个句柄后。
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
().
Never use existing files for QSharedMemory keys, as the old Qt application may attempt to remove it. Instead, let QSharedMemory create it.
Interoperability with non-Qt applications is possible, with some limitations:
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 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 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 .
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.