C / C ++で記述されたアプリケーション間でメモリを共有する方法


9

ロボット工学の制御のために、C / C ++で書かれたプログラムを実行しています。基本的に、3つの異なるプログラムが同時に実行され、共有メモリを介して通信します。私が見つけた周りのグーグルリンギングは、vxWorksやboostライブラリのプロセス間ヘッダーのようなものだ(Boostのドキュメント:プロセス間でのメモリの共有)。

今、私は実装を見たくありません、上のリンクを読むことができます。しかし、boostライブラリがこれをどのように実行するかについて、頭を動かすことはできません。つまり、1つのアプリケーションがメモリを割り当て、他のアプリケーションがそのメモリにアクセスしますが、それらはどのように通信しますか?これを行うのは危険ではありませんか?


あなたが参照したドキュメントで何が不明瞭に見えますか?「オブジェクトをマップされた領域に配置し、その領域をすべてのプロセスで異なるアドレスにマッピングする場合、生のポインターは問題を配置したプロセスに対してのみ有効であるため、問題になります。これを解決するために、Boost.Interprocessは特別なスマートポインターを提供します生ポインターの代わりに使用できます。そのため、生ポインター(または生ポインターを内部で所有するBoostスマートポインター)を含むユーザークラスは、プロセス共有マップ領域に安全に配置できません。これらのポインターは、...に置き換える必要があります。 "
gnat

オペレーティングシステムは、実際にメモリを管理するプロセスであることを忘れないでください。1日の終わりにメモリを割り当てて使用するプロセスは、OSを使用して要求を行います。OSはマルチプロセッシングを管理し、競合が発生しないようにします。
Rob Sedgwick

@gnat実装は明確です。Boostがその実装をどのようにしてこれらのドキュメントに作成しないのか...私はそれを複製したくありません(ばかげているでしょう)が、それを理解したいとは思いません。
コーシー、2015

回答:


11

しかし、boostライブラリがこれをどのように実行するかについて、頭を動かすことはできません。

ブーストプロセス間メカニズムには、機能するために3つの必要なコンポーネントがあります。

  1. メモリマップファイル:メモリマップファイルを作成し、boost.interprocessアロケーターに渡す必要があります。このアロケーターは、ファイルのチャンクを取得し、それらがstd :: allocatorによって返されたかのように使用します。マッピングは、メモリーがインプロセス固有のメモリーと互換性があるように適用されます。

  2. boost.interprocessコンテナー; この種類のコンテナーは、アロケーターによって返されたメモリを使用し、std :: containerのようなインターフェイス(begin / end / size / push_backなど)を提供します。

  3. 同期メカニズム; これは任意のプロセス間ミューテックスにすることができ、データアクセスの競合状態を防ぐために使用する必要があります。

つまり、1つのアプリケーションがメモリを割り当て、他のアプリケーションがそのメモリにアクセスしますが、それらはどのように通信しますか?これを行うのは危険ではありませんか?

割り当てられたメモリは、実際には共有メモリマップファイルです。通信は間接的であり、必要に応じて両方のアプリケーションがデータを設定または読み取ります。安全性は、プロセス間同期プリミティブを使用することによってもたらされます。


2
注目に値する:これら3つのIPCメカニズムはすべてカーネルサポートを必要とするので、これがどのように行われるを知りたい人は(OPが示すように)、個々のアプリケーションだけで行うことはできません。アプリケーションは、ファイルをメモリマップするか、他のプロセスと同期するようカーネルに要求する必要があります。
Cort Ammon

5

共有メモリはIPCの全体像ではなく、そのデータ受け渡しメカニズムですが、一部のデータが更新されており、読み取り可能であることを他のプロセスに通知する方法が必要です。これをどのように行うかはあなた次第であり、通常はOSミューテックスまたはイベントオブジェクトを使用します。各プロセスはこれが設定されるのを待機し、アプリケーションの書き込みは書き込みが完了すると設定します。次に、他のプログラムのスレッドが起動して読み取ります。

または、ポーリングして定期的にデータを読み取り、データが更新されたときに変化する値を求めます(例:増分カウンター)。


4

Boostは、ファイルのメモリマッピングを使用します。

UNIXとWindowsはどちらも、この目的のためだけに、通常のファイルシステムには存在しないファイルの作成をサポートしています。

次に、別のスレッドがメモリにアクセスする場合と同様に、そのメモリへのアクセスを同期する必要があります。同時読み取りは同期せずに発生する可能性がありますが、1つのプロセスが書き込みを行うとすぐに、他のプロセスがアクセスできないようにする必要があります。

ロックレス同期が必要な場合でも、共有メモリでのアトミック操作は可能です。


「共有メモリでのアトミック操作は、ロックレス同期が必要な場合でも可能です」を詳しく説明できますか?つまり、各プログラムがC ++の場合、2つのプログラムのそれぞれでC ++ 11 std::atomicテンプレートクラス(cplusplus.com/reference/atomic)を使用して、共有スペースに書き込めるようにする必要があります。ロックを介して同期が強制されていませんか?
ガブリエルステープルズ2017

@GabrielStaplesええか同等の原子組み込み関数
ラチェットフリーク

もう一度お邪魔してすみません。私は「原子の組み込み」に精通していません。それらをさらに研究するための参照を私に教えてもらえますか?簡単なグーグル検索は不明確です。
ガブリエルステープルズ2017

3

共有メモリは依然として単なるメモリです。ミューテックス、スピンロック、またはその他の同期プリミティブをそこに配置し、スレッドがそれらのプリミティブを使用して、それらに見えるメモリへのアクセスを同期するのとまったく同じように、共有メモリへのプロセスのアクセスを同期することができます。

実際の違いは次のとおりです。

  1. スレッドはすべてのメモリと同じアドレス空間を共有するため、生のポインタがそれらに対して機能します。プロセス間で共有されるメモリはまったく同じように機能しますが、プロセスごとに異なるアドレスにマッピングされる可能性があるため、プロセス間で生のポインタを単純に渡すことはできません

    • NB。これは、仮想メソッドの実装の詳細、実行時の型情報、およびその他のC ++メカニズムにノックオン効果をもたらします。共有メモリに仮想メソッドや動的キャストを含まない、単純に初期化可能な(プレーンな古いデータ)タイプに固執し、typeidを使用しないでください。問題はありません。
  2. 一部の同期プリミティブは、プロセス間で正しく機能するために特別なフラグまたは属性を必要とする場合があります(PTHREAD_PROCESS_SHAREDたとえば、POSIXスレッドミューテックスの属性を参照してください)。これは実際にはメモリと同期自体とは関係ありませんが、スリープしているウェイターをウェイクアップするために必要なカーネルとスケジューラの相互作用が原因です。


そう:

しかし、彼らはどのように通信しますか?

異なるスレッドが同じ方法で通信するため、上記の警告に対応

これを行うのは危険ではありませんか?

はい、スレッドが共有メモリを介して通信するのと同じように、プロセスが共有メモリを介して通信することは安全ではありません。安全にするために同等の(または同一の)同期が必要です。


3

CとC ++は異なる言語であることに注意してください。

純粋に標準の C11、またはC ++ 11(標準で定義されていないため)、またはC ++ 14n3690ドラフト、およびおそらく公式の標準)でマルチスレッド以外の共有メモリについて言及していない場合、共有メモリは不可能です。 )。したがって、共有メモリを取得するには追加のライブラリが必要です。ただし、一部のオペレーティングシステムは共有メモリをサポートしています。そのため、既存のオペレーティングシステムサービスの上に構築された共有メモリを提供するいくつかのライブラリが存在します。POCOフレームワークライブラリ(OS固有の詳細を抽象化する)の使用を検討することもできます。

Linux(およびおそらくPOSIX)の場合は、shm_overview(7)を調べてください。同期する必要があるため、sem_overview(7)も参照してください

VXWorks(私は知らないが、ググった)はVxMPを持っている

実際に何が起こっているのかを注意深く理解する必要があります。struct(C ++クラスではなく)単純な古いデータのみを共有する必要があり、アドレス(各プロセスが共通の共有メモリセグメントに対して異なるアドレスを取得する可能性があります)と同期について非常に注意する必要があります。

または、スレッドを使用します。C ++ 11標準がスレッドライブラリを定義していることに注意してください。


1
もちろん、その共有メモリはC ++ 11とC11の両方で可能です!それが標準の一部ではないという事実は無意味です。GUIも標準の一部ではありません。共有メモリとさまざまな同期方法を使用できるいくつかのクロスプラットフォームのライブラリがいくつかあります...
AK_

1
私の指摘は、共有メモリはC ++ 11標準では定義されていないということでした(ただし、一部の実装ではOS固有のサービスを通じて共有メモリを使用しています)
Basile Starynkevitch

「言語標準」という用語が実際に何を意味するのか、標準に準拠した実装とは何か、ライブラリとは何かを理解するために時間をかける必要があると思います。
AK_

共有メモリについて説明しているC ++ 11標準(またはC ++ 14のn3690ドラフト)のセクションを参照してください。
Basile Starynkevitch、2015

3
私たちは両方とも同意すると思いますが、標準のC ++ 11の意味については同意しないかもしれません。私にとっては、これはISO C ++ 11標準(またはそれに相当するフリードラフト)に過ぎません。外部ライブラリは、それらが一般的でクロスプラットフォームであっても、標準としてはカウントされません。
Basile Starynkevitch、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.