web-dev-qa-db-ja.com

共有メモリまたはmmap-LinuxC / C ++ IPC

コンテキストはプロセス間通信であり、1つのプロセス(「サーバー」)が同じマシンで実行されている多くのリスニングプロセス(「クライアント」)に固定サイズの構造体を送信する必要があります。

私はソケットプログラミングでこれを行うのに非常に快適です。サーバーとクライアント間の通信を高速化し、コピー数を減らすために、共有メモリ(shm)またはmmapsを使用してみてください。

OSはRHEL64ビットです。

私は初心者なので、どちらを使うべきか提案してください。誰かが私に本やオンラインリソースを教えて同じことを学ぶことができれば幸いです。

答えてくれてありがとう。サーバー(Market Data Server)は通常、マルチキャストデータを受信するため、1秒あたり約200,000の構造体が「クライアント」に「送信」されます。各構造体は約100バイトです。 shm_open/mmapの実装は、データの大きなブロックまたは大量の小さな構造体に対してのみソケットよりも優れていますか?

15
Humble Debugger

mmapshm_openと一緒に使用して、共有メモリをプロセスの仮想アドレス空間にマップします。これは比較的直接的でクリーンです。

  • 共有メモリセグメントを、"/myRegion"のようなある種の記号名で識別します。
  • shm_openを使用して、その領域でファイル記述子を開きます
  • ftruncateを使用すると、セグメントを必要なサイズに拡大できます
  • mmapを使用して、アドレス空間にマップします

shmatおよびCoインターフェースには、(少なくとも歴史的に)マップできるメモリの最大量に制限があるという欠点があります。

次に、すべてのPOSIXスレッド同期ツール(pthread_mutex_tpthread_cond_tsem_tpthread_rwlock_t、...)には、共有プロセスでそれらを使用できる初期化インターフェイスがあります。コンテキストも。最新のLinuxディストリビューションはすべてこれをサポートしています。

これがソケットよりも好ましいかどうか?パフォーマンスに関しては、物事をコピーする必要がないため、少し違いが生じる可能性があります。しかし、私が推測する主なポイントは、セグメントを初期化すると、これは概念的に少し単純になるということです。アイテムにアクセスするには、共有ロックをロックし、データを読み取ってから、もう一度ロックを解除する必要があります。

@Rが示唆しているように、複数のリーダーがある場合は、pthread_rwlock_tがおそらく使用するのに最適なロック構造になります。

22
Jens Gustedt

私はかつて共有メモリセグメントを使用してIPCライブラリを実装しました。これにより、コピーを回避できました(送信側メモリからカーネル空間に、次にカーネル空間から受信側メモリにデータをコピーする代わりに、送信者から受信者のメモリに直接コピーできます)。

とにかく、結果は私が期待していたほど良くありませんでした。TLBエントリの再マッピングとその他すべてが非常に高価であるため、実際にメモリセグメントを共有することは非常に費用のかかるプロセスでした。詳細については、 このメール を参照してください(私はそのような人ではありませんが、ライブラリの開発中にそのようなメールを受け取りました)。

結果は、非常に大きなメッセージ(たとえば、数メガバイト以上)に対してのみ良好でした。小さなバッファーで作業している場合、カーネルモジュールを作成する意思がない限り、UNIXソケットが最も最適化されたものです。

7
peoro

すでに提案されていることとは別に、別の方法を提供したいと思います。IPv6ノード/インターフェイスローカルマルチキャスト、つまりループバックインターフェイスに制約されたマルチキャストです。 http://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xml#ipv6-multicast-addresses-1

最初はこれはかなり重いように思われるかもしれませんが、ほとんどのOSはゼロコピーアーキテクチャでループバックソケットを実装しています。 bufに渡されたsendパラメータにマップされたページには、追加のマッピングが割り当てられ、コピーオンライトとしてマークされます。これにより、送信プログラムがその中のデータを上書きしたり、コンテンツの割り当てを解除したりします。保存されます。

生の構造体を渡す代わりに、堅牢なデータ構造を使用する必要があります。 Netstrings http://cr.yp.to/proto/netstrings.txt およびBSON http://bsonspec.org/ が頭に浮かびます。

7
datenwolf

POSIX shm_open/mmapインターフェイスと古いSystemV shmopインターフェイスのどちらを選択しても、大きな違いはありません。初期化システムコールの後、同じ状況、つまりメモリ領域が発生するためです。さまざまなプロセス間で共有されます。お使いのシステムがそれをサポートしている場合は、shm_open/mmapを使用することをお勧めします。これは、より適切に設計されたインターフェースだからです。

次に、共有メモリ領域を、すべてのプロセスがデータを落書きできる共通の黒板として使用します。難しいのは、この領域にアクセスするプロセスを同期することです。ここでは、非常に困難でエラーが発生しやすい独自の同期スキームを作成しないことをお勧めします。代わりに、プロセス間のアクセスを同期するために既存の作業ソケットベースの実装を使用し、プロセス間で大量のデータを転送するためにのみ共有メモリを使用します。このスキームでも、バッファの割り当てを調整するための中央プロセスが必要になるため、転送するデータが非常に大量にある場合にのみ、このスキームは価値があります。または、 Boost.Interprocess のような同期ライブラリを使用します。

2