QSharedMemory 類

QSharedMemory 類提供對共享內存段的訪問。 更多...

頭: #include <QSharedMemory>
CMake: find_package(Qt6 REQUIRED COMPONENTS Core)
target_link_libraries(mytarget PRIVATE Qt6::Core)
qmake: QT += core
繼承: QObject

公共類型

enum AccessMode { ReadOnly, ReadWrite }
enum SharedMemoryError { NoError, PermissionDenied, InvalidSize, KeyError, AlreadyExists, …, UnknownError }

公共函數

QSharedMemory (const QString & key , QObject * parent = nullptr)
QSharedMemory (QObject * parent = nullptr)
virtual ~QSharedMemory ()
bool attach (QSharedMemory::AccessMode mode = ReadWrite)
const void * constData () const
bool create (qsizetype size , QSharedMemory::AccessMode mode = ReadWrite)
void * data ()
const void * data () const
bool detach ()
QSharedMemory::SharedMemoryError error () const
QString errorString () const
bool isAttached () const
QString key () const
bool lock ()
QString nativeKey () const
void setKey (const QString & key )
void setNativeKey (const QString & key )
qsizetype size () const
bool unlock ()

詳細描述

QSharedMemory 提供對多綫程和進程共享內存段的訪問。它還為單綫程 (或進程) 提供鎖定內存的獨占訪問手段。

當使用此類時,要意識到以下平颱差異:

  • Windows:QSharedMemory 不 "擁有" 共享內存段。當擁有 QSharedMemory 實例 (被附加到特定共享內存段) 的所有綫程 (或進程) 銷毀 QSharedMemory 實例 (或退齣) 時,Windows 內核會自動釋放共享內存段。
  • Unix: QSharedMemory "owns" the shared memory segment. When the last thread or process that has an instance of QSharedMemory attached to a particular shared memory segment detaches from the segment by destroying its instance of QSharedMemory, the destructor releases the shared memory segment. But if that last thread or process crashes without running the QSharedMemory destructor, the shared memory segment survives the crash.
  • Unix: QSharedMemory can be implemented by one of two different backends, selected at Qt build time: System V or POSIX. Qt defaults to using the System V API if it is available, and POSIX if not. These two backends do not interoperate, so two applications must ensure they use the same one, even if the native key (see setNativeKey ()) is the same.

    The POSIX backend can be explicitly selected using the -feature-ipc_posix option to the Qt configure script. If it is enabled, the QT_POSIX_IPC macro will be defined.

  • Sandboxed applications on Apple platforms (including apps shipped through the Apple App Store): This environment requires the use of POSIX shared memory (instead of System V shared memory).

    Qt for iOS is built with support for POSIX shared memory out of the box. However, Qt for macOS builds (including those from the Qt installer) default to System V, making them unsuitable for App Store submission if QSharedMemory is needed. See above for instructions to explicitly select the POSIX backend when building Qt.

    In addition, in a sandboxed environment, the following caveats apply:

    • The key must be in the form <application group identifier>/<custom identifier> , as documented here and here .
    • The key length is limited to 30 characters.
    • On process exit, the named shared memory entries are not cleaned up, so restarting the application and re-creating the shared memory under the same name will fail. To work around this, fall back to attaching to the existing shared memory entry:
      QSharedMemory shm("DEVTEAMID.app-group/shared");
      if (!shm.create(42) && shm.error() == QSharedMemory::AlreadyExists)
          shm.attach();
      								
  • Android: QSharedMemory is not supported.

記得鎖定共享內存采用 lock () 在讀寫共享內存之前,和記住釋放鎖采用 unlock () 在完成後。

QSharedMemory 自動銷毀共享內存段,當從段分離最後 QSharedMemory 實例時,且不保留段引用。

警告: QSharedMemory 以特定 Qt 方式改變鍵,除非另外指定。與非 Qt 應用程序的互操作的達成是通過首先創建默認共享內存采用 QSharedMemory(),然後設置本機鍵采用 setNativeKey (), after ensuring they use the same low-level API (System V or POSIX). When using native keys, shared memory is not protected against multiple accesses on it (for example, unable to lock ()) 且應該使用用戶定義機製來達成這種保護。

Alternative: Memory-Mapped File

Another way to share memory between processes is by opening the same file using QFile and mapping it into memory using QFile::map () (without specifying the QFileDevice::MapPrivateOption option). Any writes to the mapped segment will be observed by all other processes that have mapped the same file. This solution has the major advantages of being independent of the backend API and of being simpler to interoperate with from non-Qt applications. And since QTemporaryFile QFile , applications can use that class to achieve clean-up semantics and to create unique shared memory segments too.

To achieve locking of the shared memory segment, applications will need to deploy their own mechanisms. This can be achieved by using QBasicAtomicInteger or std::atomic in a pre-determined offset in the segment itself. Higher-level locking primitives may be available on some operating systems; for example, on Linux, pthread_mutex_create() can be passed a flag to indicate that the mutex resides in a shared memory segment.

A major drawback of using file-backed shared memory is that the operating system will attempt to write the data to permanent storage, possibly causing noticeable performance penalties. To avoid this, applications should locate a RAM-backed filesystem, such as tmpfs on Linux (see QStorageInfo::fileSystemType ()), or pass a flag to the native file-opening function to inform the OS to avoid committing the contents to storage.

File-backed shared memory must be used with care if another process participating is untrusted. The files may be truncated/shrunk and cause applications accessing memory beyond the file's size to crash.

Linux hints on memory-mapped files

On modern Linux systems, while the /tmp directory is often a tmpfs mount point, that is not a requirement. However, the /dev/shm directory is required to be a tmpfs and exists for this very purpose. Do note that it is world-readable and writable (like /tmp and /var/tmp ), so one must be careful of the contents revealed there. Another alternative is to use the XDG Runtime Directory (see QStandardPaths::writableLocation () 和 QStandardPaths::RuntimeLocation ), which on Linux systems using systemd is a user-specific tmpfs .

An even more secure solution is to create a "memfd" using memfd_create(2) and use interprocess communication to pass the file descriptor, like QDBusUnixFileDescriptor or by letting the child process of a QProcess inherit it. "memfds" can also be sealed against being shrunk, so they are safe to be used when communicating with processes with a different privilege level.

FreeBSD hints on memory-mapped files

FreeBSD also has memfd_create(2) and can pass file descriptors to other processes using the same techniques as Linux. It does not have temporary filesystems mounted by default.

Windows hints on memory-mapped files

On Windows, the application can request the operating system avoid committing the file's contents to permanent storage. This request is performed by passing the FILE_ATTRIBUTE_TEMPORARY flag in the dwFlagsAndAttributes CreateFile Win32 function, the _O_SHORT_LIVED flag to _open() low-level function, or by including the modifier "T" to the fopen() C runtime function.

There's also a flag to inform the operating system to delete the file when the last handle to it is closed ( FILE_FLAG_DELETE_ON_CLOSE , _O_TEMPORARY , and the "D" modifier), but do note that all processes attempting to open the file must agree on using this flag or not using it. A mismatch will likely cause a sharing violation and failure to open the file.

成員類型文檔編製

enum QSharedMemory:: AccessMode

常量 描述
QSharedMemory::ReadOnly 0 共享內存段是隻讀的。不允許寫入共享內存段。嘗試寫入采用 ReadOnly 創建的共享內存段,會導緻程序中止。
QSharedMemory::ReadWrite 1 允許讀寫共享內存段。

enum QSharedMemory:: SharedMemoryError

常量 描述
QSharedMemory::NoError 0 沒有齣現錯誤。
QSharedMemory::PermissionDenied 1 操作失敗,因為調用者沒有所需權限。
QSharedMemory::InvalidSize 2 創建操作失敗,因為請求大小無效。
QSharedMemory::KeyError 3 操作失敗,因為鍵無效。
QSharedMemory::AlreadyExists 4 A create () 操作失敗,因為具有指定鍵的共享內存段已存在。
QSharedMemory::NotFound 5 An attach () 失敗,因為找不到具有指定鍵的共享內存段。
QSharedMemory::LockError 6 試圖 lock () 共享內存段失敗,因為 create () 或 attach () 失敗和返迴 false,或因為發生係統錯誤在 QSystemSemaphore::acquire ().
QSharedMemory::OutOfResources 7 A create () 操作失敗,因為沒有足夠內存可用於填充請求。
QSharedMemory::UnknownError 8 發生其它事情且很糟糕。

成員函數文檔編製

QSharedMemory:: QSharedMemory (const QString & key , QObject * parent = nullptr)

構造共享內存對象采用給定 parent 並將其鍵設為 key 。因為有設置鍵,其 create () 和 attach () 函數可以被調用。

另請參閱 setKey (), create (),和 attach ().

QSharedMemory:: QSharedMemory ( QObject * parent = nullptr)

此函數重載 QSharedMemory()。

構造共享內存對象采用給定 parent 。由於構造函數未設置共享內存對象的鍵,因此,共享內存對象沒有附加底層共享內存段。必須設置鍵采用 setKey () 或 setNativeKey () 先於 create () 或 attach () 可以使用。

另請參閱 setKey ().

[虛擬] QSharedMemory:: ~QSharedMemory ()

析構函數清零鍵,強製共享內存對象 detach 從其底層共享內存段。若此共享內存對象是連接到共享內存段的最後一個, detach () 操作會銷毀共享內存段。

另請參閱 detach () 和 isAttached ().

bool QSharedMemory:: attach ( QSharedMemory::AccessMode mode = ReadWrite)

試圖將進程附加到共享內存段,通過傳遞給構造函數的鍵標識或調用 setKey () 或 setNativeKey ()。訪問 mode is ReadWrite 默認情況下。它還可以為 ReadOnly 。返迴 true 若附加操作成功。若返迴 false,調用 error () 以確定發生何種錯誤。在附加共享內存段後,可以獲得共享內存的指針通過調用 data ().

另請參閱 isAttached (), detach (),和 create ().

const void *QSharedMemory:: constData () const

返迴共享內存段內容的 const 指針,若有附加一個的話。否則,返迴 null。記得鎖定共享內存采用 lock () 在讀寫共享內存之前,和記住釋放鎖采用 unlock () 在完成後。

另請參閱 attach () 和 create ().

bool QSharedMemory:: create ( qsizetype size , QSharedMemory::AccessMode mode = ReadWrite)

創建共享內存段 size 字節采用傳遞給構造函數的鍵,設置采用 setKey () 或設置采用 setNativeKey (),然後附加到新共享內存段采用給定訪問 mode 並返迴 true 。若由鍵標識的共享內存段已存在,不履行附加操作和 false 被返迴。當返迴值為 false ,調用 error () 以確定發生何種錯誤。

另請參閱 error ().

void *QSharedMemory:: data ()

返迴共享內存段內容的 const 指針,若有附加一個的話。否則,返迴 null。記得鎖定共享內存采用 lock () 在讀寫共享內存之前,和記住釋放鎖采用 unlock () 在完成後。

另請參閱 attach ().

const void *QSharedMemory:: data () const

此函數重載 data()。

bool QSharedMemory:: detach ()

從共享內存段分離進程。若這是附加到共享存儲段的最後進程,則共享存儲段由係統釋放 (即:銷毀內容)。函數返迴 true 若它分離瞭共享內存段。若它返迴 false ,通常意味著段未被附加或被另一進程鎖定。

另請參閱 attach () 和 isAttached ().

QSharedMemory::SharedMemoryError QSharedMemory:: error () const

返迴指示是否發生錯誤的值,且若如此,指示錯誤是什麼。

另請參閱 errorString ().

QString QSharedMemory:: errorString () const

返迴最後發生錯誤的文本描述。若 error () 返迴 錯誤值 ,調用此函數以獲取描述錯誤的文本字符串。

另請參閱 error ().

bool QSharedMemory:: isAttached () const

返迴 true 若此進程被附加到共享內存段。

另請參閱 attach () 和 detach ().

QString QSharedMemory:: key () const

返迴的鍵賦值采用 setKey () 到此共享內存,或 null 鍵若尚未賦值鍵,或段使用的是 nativeKey ()。鍵是 Qt 應用程序用來標識共享內存段的標識符。

可以找到由操作係統使用的本機、特定平颱鍵,通過調用 nativeKey ().

另請參閱 setKey () 和 setNativeKey ().

bool QSharedMemory:: lock ()

這是鎖供此進程訪問的共享內存段的信號量,並返迴 true 。若另一進程已鎖定段,此函數阻塞直到鎖被釋放為止。然後,獲取鎖並返迴 true 。若此函數返迴 false ,意味著已忽略的 false 返迴來自 create () 或 attach (),已設置鍵采用 setNativeKey () 或 QSystemSemaphore::acquire () 失敗由於未知係統錯誤。

另請參閱 unlock (), data (),和 QSystemSemaphore::acquire ().

QString QSharedMemory:: nativeKey () const

返迴用於此共享內存對象的本機、特定平颱鍵。本機鍵是操作係統用於標識共享內存段的標識符。

可以使用本機鍵訪問 Qt 尚未創建的共享內存段,或將共享內存訪問授予非 Qt 應用程序。

另請參閱 setKey () 和 setNativeKey ().

void QSharedMemory:: setKey (const QString & key )

設置平颱無關 key 為此共享內存對象。若 key 與當前鍵相同,函數將什麼都不做而返迴。

可以調用 key () 以檢索平颱無關鍵。在內部, QSharedMemory 將此鍵轉換成平颱特定鍵。若改為調用 nativeKey (),將獲得特定平颱的轉換鍵。

若將共享內存對象附加到底層共享內存段,它將 detach 從其,在設置新鍵之前。此函數不做 attach ().

另請參閱 key (), nativeKey (),和 isAttached ().

void QSharedMemory:: setNativeKey (const QString & key )

設置特定平颱本機 key 為此共享內存對象。若 key 與當前本機鍵相同,函數將什麼都不做而返迴。若隻想為段賦值鍵,應調用 setKey () 代替。

可以調用 nativeKey () 以檢索本機鍵。若有賦值本機鍵,調用 key () 將返迴 null 字符串。

若將共享內存對象附加到底層共享內存段,它將 detach 從其,在設置新鍵之前。此函數不做 attach ().

應用程序將不可移植,若設置本機鍵。

另請參閱 nativeKey (), key (),和 isAttached ().

qsizetype QSharedMemory:: size () const

返迴共享內存段的附加大小。若未附加共享內存段,返迴 0。

注意: 段大小可能大於請求大小,被傳遞給 create ().

另請參閱 create () 和 attach ().

bool QSharedMemory:: unlock ()

釋放共享內存段鎖並返迴 true ,若鎖目前由此進程保持。若段未被鎖定,或鎖由另一進程所保持,則什麼也不會發生並返迴 false。

另請參閱 lock ().