メモリの共有
Qt は、同じシステム内の他のプロセスとメモリを共有するための 2 つのテクニックを提供します:QSharedMemory と、QFile を使ったメモリマップファイルです。他のプロセスと共有されるメモリは、しばしば「セグメント」と呼ばれます。以前は、セグメント化されたメモリモデルを持つプロセッサ上で、特定のセグメントとして実装されていたかもしれませんが、現代のオペレーティングシステムではそうではありません。共有メモリー・セグメントは、オペレーティング・システムが、参加するすべてのプロセスが利用できるようにする、単なるメモリーの領域です。
注意: セグメントをメモリ上に配置するアドレスは、共有に参加するプロセスごとに異なることがほとんどです。したがって、アプリケーションは、プリミティブ C++ 型やそのような型の配列など、位置に依存しないデータのみを共有するように注意する必要があります。
QSharedMemory を使用したメモリの共有
QSharedMemory は、指定されたサイズの共有メモリ・セグメントを作成したり、他のプロセスによって作成されたセグメントにアタッチしたりするためのシンプルな API を提供します。さらに、内部メソッド を使用して、セグメント全体を および するためのメソッドも提供します。QSystemSemaphore lock unlock
QNativeIpcKey 共有メモリ・セグメントとシステム・セマフォは、「キー」によってシステム内でグローバルに識別されます。さらに、OSによっては、Qtはメモリを共有するための複数の異なるバックエンドをサポートすることがあります。詳細と制限については、Native IPC Keysのドキュメントを参照してください。
QSharedMemory は、同じ特権レベル内でのみメモリを共有するように設計されています(つまり、他のユーザーによって起動されたプロセスなど、信頼されていない他のプロセスとは共有できません)。これをサポートするバックエンドの場合、 は同じ特権レベルのプロセスだけがアタッチできるようにセグメントを作成します。QSharedMemory
メモリマップされたファイルによるメモリの共有
ほとんどのファイルはQFile::map() を使ってメモリにマップすることができる。MapPrivateOption オプションが指定されていない場合、マップされたセグメントへの書き込みは、同じファイルをマップした他のすべてのプロセスによって観測される。メモリにマッピングできるファイルの例外として、ネットワーク共有にあるリモート・ファイルや、特定のファイルシステムにあるファイルがある。オペレーティング・システムがリモート・ファイルのメモリへのマッピングを許可している場合でも、ファイルに対するI/O操作はキャッシュされ、遅延する可能性が高いため、真のメモリ共有は不可能である。
このソリューションには、バックエンド API に依存せず、Qt 以外のアプリケーションとの相互運用がより簡単であるという大きな利点があります。QTemporaryFile はQFile であるため、アプリケーションはこのクラスを使用してクリーンアップ・セマンティクスを実現し、一意の共有メモリ・セグメントを作成することもできます。
共有メモリ・セグメントのロックを実現するために、アプリケーションは独自のメカニズムを導入する必要があります。一つの方法は、QLockFile を使うことである。また、QBasicAtomicInteger を使用するか、std::atomic
をセグメント自体にあらかじめ決められたオフセットに設定するのも、コストのかからない解決策です。例えばLinuxでは、アプリケーションはpthread_mutex_create()
に渡されるミューテックス属性に "pshared "フラグを設定することで、ミューテックスが共有メモリセグメントに存在することを示すことができる。
オペレーティング・システムは、共有メモリに書き込まれた書き込みを永続的な記憶域にコミットしようとする可能性が高いことに注意してください。これは望ましいことかもしれないが、ファイル自体が一時的なものである場合には、パフォーマンス上のペナルティになるかもしれない。そのような場合、アプリケーションは、Linuxのtmpfs
(QStorageInfo::fileSystemType ()を参照)のようなRAMバッキング・ファイルシステムを見つけるか、ネイティブのファイルオープン関数にフラグを渡して、OSに内容をストレージにコミットしないように通知する必要がある。
ファイルバックされた共有メモリーを使用して、信頼できないプロセスと通信することは可能であるが、その場合、アプリケーションは細心の注意を払う必要がある。ファイルが切り捨てられたり縮小されたりして、ファイル・サイズを超えるメモリにアクセスするアプリケーションがクラッシュする可能性がある。
メモリー・マップド・ファイルに関するLinuxのヒント
最近のLinuxシステムでは、/tmp
ディレクトリがtmpfs
マウント・ポイントになることがよくありますが、これは必須条件ではありません。しかし、/dev/shm
ディレクトリは、tmpfs
である必要があり、まさにメモリーを共有する目的で存在します。このディレクトリは(/tmp
や/var/tmp
のように)ワールドリーダブルであり、書き込み可能であることに注意してください。別の方法として、XDG Runtime Directory(QStandardPaths::writableLocation ()およびQStandardPaths::RuntimeLocation ()を参照)を使用することもできます。systemdを使用しているLinuxシステムでは、ユーザー固有のtmpfs
。
さらに安全な解決策は、memfd_create(2)
を使用して "memfd" を作成し、QDBusUnixFileDescriptor のようにプロセス間通信を使用してファイル・ディスクリプタを渡すか、QProcess の子プロセスに継承させることである。"memfd" はシュリンクされないように封印することもできるので、 異なる特権レベルのプロセスと通信する際にも安全に使うことができます。
メモリマップされたファイルに関する FreeBSD のヒント
FreeBSD にもmemfd_create(2)
があり、Linux と同じ手法でファイルディスクリプタを他のプロセスに渡すことができます。デフォルトでは一時ファイルシステムはマウントされていません。
Windows メモリマップドファイルのヒント
Windowsでは、アプリケーションはオペレーティング・システムに対して、ファイルの内容を永久記憶装置に保存しないように要求することができる。この要求は、CreateFile
Win32関数のdwFlagsAndAttributes
パラメータにFILE_ATTRIBUTE_TEMPORARY
フラグを渡すか、_open()
低レベル関数に_O_SHORT_LIVED
フラグを渡すか、fopen()
Cランタイム関数に修飾子 "T "を含めることで実行される。
また、ファイルへの最後のハンドルが閉じられたときにファイルを削除するようオペレーティング・システムに通知するフラグもある(FILE_FLAG_DELETE_ON_CLOSE
、_O_TEMPORARY
、"D "修飾子)。不一致の場合、共有違反が発生し、ファイルを開けなくなる可能性があります。
本ドキュメントに含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。