ネイティブIPCキー

QSharedMemoryQSystemSemaphore クラスは、「キー」として知られるシステム全体の識別子を使用してリソースを識別します。低レベルのキー値とキータイプは、QNativeIpcKey クラスを使用して Qt にカプセル化されます。このクラスは、QNativeIpcKey::toString() やQNativeIpcKey::fromString() によって、他のプロセスとキーを交換するための適切な手段も提供します。

Qtは現在、この2つのクラスに対して3つの異なるバックエンドをサポートしており、QNativeIpcKey::Type の列挙で利用可能な値と一致しています。

  • POSIX リアルタイム拡張 (IEEE 1003.1b, POSIX.1b)
  • X/Open System Interfaces (XSI)またはSystem V (SVr4)。
  • Windowsプリミティブ

その名前が示すように、WindowsプリミティブはWindowsオペレーティングシステム上でのみ利用可能であり、デフォルトのバックエンドである。他の2つは通常Unixオペレーティングシステムで利用可能である。以下の表は、Qt 6.6 以降で利用可能なプリミティブの概要です:

オペレーティングシステムPOSIXシステム VWindows
Android
インテグリティ
QNXはい
macOSはい通常 (1)
その他のApple OSはい
その他のUnixシステムはいはい
ウィンドウズまれに (2)あり

注: 1 サンドボックス化されたmacOSアプリケーション(Apple App Store経由で配布されるすべてのアプリケーションを含む)は、System Vオブジェクトを使用できない。

注: 2 WindowsのGCC互換Cランタイムの中には、POSIX互換の共有メモリ・サポートを提供するものがあるが、これはまれである。Microsoftコンパイラでは常にありません。

指定されたキー・タイプがサポートされているかどうかを判断するには、アプリケーションは QSharedMemory::isKeyTypeSupported() および QSystemSemaphore::isKeyTypeSupported() を呼び出す必要があります。

QNativeIpcKey また、導入前の Qt アプリケーションとの互換性もサポートしています。以下のセクションでは、バックエンドの制限事項、文字列キーの内容、互換性について詳しく説明します。

クロスプラットフォームの安全なキーフォーマット

QNativeIpcKey::setNativeKey() とQNativeIpcKey::nativeKey() は低レベルのネイティブ・キーを扱います。このキーはネイティブ API で使用したり、Qt 以外のプロセスと共有したりすることができます(API については後述します)。このフォーマットは通常クロスプラットフォームではないので、QSharedMemoryQSystemSemaphore は、クロスプラットフォームの識別子文字列をネイティブキーに変換する関数を提供します:QSharedMemory::platformSafeKey() と QSystemSemaphore::platformSafeKey() です。

ほとんどのプラットフォームでのクロスプラットフォーム・キーの長さはファイル名と同じですが、Appleプラットフォームでは使用可能な長さが30バイトに制限されます(US-ASCII以外の文字を使用する場合はUTF-8エンコーディングに注意してください)。つまり、ファイル名で許可されていない文字、特にパスコンポーネントを区切る文字(スラッシュとバックスラッシュ)を含んではならない。以下はクロスプラットフォームのキーの良い例です:「myapp」、「org.example.myapp」、「org.example.myapp-12345」。キーのサイズが大きくならないようにすることと、キーがそれぞれのプラットフォームで有効な文字を含んでいることを確認することは、呼び出し側次第であることに注意してください。Qtは長すぎるキーを黙って切り捨てます。

Appleのサンドボックスの制限:アプリケーションがAppleオペレーティングシステムのサンドボックス内で動作している場合、キーは非常に特殊な形式でなければなりません:<application group identifier>/<custom identifier> 。Apple App Store を通じて配布されるすべてのアプリケーションには、サンドボックス化が暗黙の了解となっています。アプリケーションのグループ識別子を取得する方法など、より詳細な情報については、アップル社のここと ここ のドキュメントを参照してください。

ネイティブキーのフォーマット

このセクションでは、サポートされているバックエンドのネイティブキーのフォーマットについて詳しく説明します。

POSIXリアルタイム

ネイティブ・キーはファイル名に似ており、スラッシュを除いてファイル名と同じ文字を使うことができます。POSIXでは、キー名の最初の文字はスラッシュでなければならない。ほとんどのOSでは、キーの長さはファイル名と同じであるが、Apple OSでは32文字に制限される(これには最初のスラッシュと終端のヌルが含まれるため、使用可能な文字は30文字しかない)。

以下は、ネイティブPOSIXキーの良い例である:"/myapp"、"/org.example.myapp"、"/org.example.myapp-12345"。

QSharedMemory::platformSafeKey()とQSystemSemaphore::platformSafeKey()は、単にスラッシュを前置します。Appleオペレーティング・システムでは、結果を利用可能なサイズに切り詰めます。

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のキーはシステム内のファイル名の形式をとるので、ファイルパスと全く同じ制限を持つ。QSharedMemoryQSystemSemaphore は、オブジェクトの作成時にこのファイルが存在しなければ作成します。自動削除が無効になっている場合、このファイルはQSharedMemoryQSystemSemaphore の間で競合することなく共有され、現存するファイルであれば何でもかまいません(例えば、プロセスの実行ファイルそのものでもかまいません、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以外ではPOSIX Realtimeオブジェクトをクリーンアップすることはありませんでした。

X/Open System Interfaces (XSI) / System V

Qtクラスによって管理されるリソースは2つあります。キーが参照するファイルと、オブジェクトそのものです。QSharedMemory 、オブジェクトを協調的に管理します。最後のアタッチメントは、オブジェクトそのものを削除し、次にキーファイルを削除します。QSystemSemaphore 、オブジェクトを削除するのは、QSystemSemaphore::Create 、渡された場合だけです。さらに、キーファイルを作成した場合は、それも削除します。

Qt 6.6以降では、どちらのクラスにもクリーンアップを行わないように要求することができます。

Windows

オペレーティング・システムはオブジェクトを所有し、オブジェクトへの最後のハンドルが閉じられた後にクリーンアップします。

古い Qt アプリケーションとの相互運用性

QNativeIpcKey クラスは Qt 6.6 で導入されました。このバージョン以前では、QSharedMemoryQSystemSemaphore のバックエンドはQt自身のビルド時に決定されていました。Windowsシステムでは、常にWindowsバックエンドでした。Unixシステムでは、コンフィギュレーションスクリプトがSystem Vバックエンドが利用可能であると判断した場合、デフォルトでSystem Vバックエンドが利用されました。利用できない場合は、POSIXバックエンドにフォールバックします。POSIXバックエンドは、Qt configureスクリプトの-feature-ipc_posix オプションを使って明示的に選択することができました。有効になっていれば、QT_POSIX_IPC マクロが定義されます。

Qt 6.6でもconfigureスクリプトのオプションは残っていますが、バックエンドの可用性を制御することはなくなりました。その代わりに、QNativeIpcKey::legacyDefaultTypeForOs()が返す内容が変更されます。互換性を維持する必要があるアプリケーションは、相互運用性を保証するために、このキータイプのみを使用する必要があります。

QSharedMemoryQSystemSemaphore の両方の API には、クロス・プラットフォーム・キーという概念がありましたが、現在は非推奨となっており、QSharedMemory::legacyNativeKey() と QSystemSemaphore::legacyNativeKey() を使用するようになっています。この2つの関数は、以前のバージョンで非推奨だった関数と同じネイティブ・キーを生成します。古いコードが例えば

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

に更新できます:

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

2つのアプリケーションがネイティブ・キーを交換した場合、このようなコードを更新する必要はありません:

QSharedMemory shm;
shm.setNativeKey(key);

しかし、古いアプリケーションが ネイティブ・キーを受け取っていた場合、新しいアプリケーションはplatformSafeKey() の第2引数にQNativeIpcKey::legacyDefaultTypeForOs()を指定することができる。

X/Open System Interfaces (XSI) / System V

QSharedMemory 古いQtアプリケーションが削除しようとするかもしれません。代わりに、QSharedMemory に作成させてください。

Qt 以外のアプリケーションとの相互運用性

いくつかの制限はありますが、Qt 以外のアプリケーションとの相互運用は可能です:

  • 共有メモリセグメントの作成が競合しないこと
  • QSharedMemory セグメントをロックするサポートはありません。

Qt 以外のアプリケーションとの通信は、常にネイティブキーを介して行わなければなりません。

QSharedMemory は常にセグメント全体をメモリにマッピングします。Qt 以外のアプリケーションは、セグメントの一部だけをメモリにマッピングすることができます。

POSIX リアルタイム

POSIX共有メモリはshm_open()でオープンでき、POSIXシステムセマフォはsem_open()でオープンできます。

これらの関数はどちらもQNativeIpcKey::nativeKey() の結果であるname パラメータを取り、QFile::encodeName() /QFile::decodeName() を使ってファイル名をエンコードする。

Windows

Windowsの共有メモリー・オブジェクトはCreateFileMappingWを使って開くことができ、Windowsのシステム・セマフォ・オブジェクトはCreateSemaphoreWを使って開くことができる。どちらの関数も "Create "で始まる名前にもかかわらず、既存のオブジェクトにアタッチすることができる。

これらの関数のlpName パラメータは、変換なしのQNativeIpcKey::nativeKey() の結果である。

海外のアプリケーションがこれらの関数の非Unicodeバージョン(末尾が "A")を使用する場合、QString を使用して名前を8ビットと変換することができます。

X/Open System Interfaces (XSI) / System V

System Vの共有メモリはshmget()で取得でき、System Vのシステム・セマフォはsemget()で取得できる。

これらの関数のkey パラメータは、QNativeIpcKey::nativeKey() からid が 81 または 0x51 (ASCII の大文字 'Q') のファイル名を渡したときのftok()関数の結果である。

System Vのセマフォ・オブジェクトは複数のセマフォを含むことができるが、QSystemSemaphore は最初のセマフォ(sem_num の場合は0番)しか使用しない。

QSharedMemoryQSystemSemaphore ともに、最後のアタッチメントである場合、IPC_RMID の操作でオブジェクトを削除し、shmctl()semctl() の操作でオブジェクトを削除するのがデフォルトです。

©2024 The Qt Company Ltd. 本書に含まれるドキュメントの著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。