1

boost::interprocess::message_queue メカニズムは、主にプロセス間通信のために設計されているようです。

問題は、メッセージ内のオブジェクトをシリアル化することです。

「メッセージ キューは、プロセス間で raw バイトをコピーするだけで、オブジェクトを送信しません。」

これにより、大きな複合オブジェクトが渡される高速で反復的なスレッド間通信にはまったく適していません。

以前に作成された既知のオブジェクトへの ref/shared_ptr/pointer を持つメッセージを作成し、あるスレッドから次のスレッドに安全に渡したいと考えています。

asio::io_service を使用してバインド完了をポストすることはできますが、それはやや不格好であり、問​​題のスレッドが asio を使用している必要があり、これは少し奇妙に思えます。

悲しいことに asio::io_service に基づいて、私はすでに自分自身を書いていますが、ブーストをサポートする一般的なメカニズムに切り替えることを好みます。

4

2 に答える 2

2

個別のプロセスには個別のアドレス空間があり、非常に特殊な場合を除いて単純にポインターを渡すことができないため、プロセス間通信用に設計されたメカニズムが必要です。std::stackスレッド通信には、 などのstd::queue標準コンテナを使用できます。またstd::priority_queue、スレッド間で通信するには、mutex を介して適切な同期を提供するだけで済みます。または、boost によって提供されるロックフリー コンテナーを使用することもできます。スレッド間通信には他に何が必要ですか?

于 2013-10-24T21:12:43.703 に答える
2

私は Boost 自体の専門家ではありませんが、特にプログラムのデータが動的に割り当てられたメモリ (かなりBoost で書かれたものにはよくあることです; 文字列は C のような単純なオブジェクトではありません...)。

クラス内のデータのコピー

メッセージキューとパイプは、実際には、あるスレッド/プロセスから別のスレッド/プロセスにバイトのコレクションを渡す方法にすぎません。通常、それらを使用するときは、データへの参照のコピー(元のデータを指す)だけでなく、元のデータのコピーで終わる宛先スレッドを探しています。

ポインターをまったく含まない単純な C 構造体を使用すると、簡単です。構造体のコピーにはすべてのデータが含まれていますが、問題ありません。しかし、文字列のような複雑なデータ型を持つ C++ クラスは、割り当てられたメモリへの参照/ポインターを含む構造体になりました。その構造をコピーしても、実際には割り当てられたメモリにデータをコピーしていません。

そこでシリアライゼーションの出番です。通常、両方のプロセスが同じメモリを共有できないプロセス間通信では、シリアライゼーションは、送信される構造体とそれが参照するすべてのデータをバイト ストリームに分割する方法として機能します。もう一方の端。スレッドの場合、2 つのスレッドが同時に同じメモリにアクセスしたくない場合も同じです。シリアル化は、コピーする必要があるものを正確に確認するためにクラスをナビゲートする手間を省く便利な方法です。

効率

Boost がシリアル化に何を使用するかはわかりませんが、明らかに XML へのシリアル化は非常に非効率的です。ASN.1 BER のようなバイナリ シリアル化は、はるかに高速です。

また、パイプやメッセージ キューを介したデータのコピーは、以前ほど非効率ではなくなりました。伝統的にプログラマーは、別のスレッドと共有するためだけにデータを繰り返しコピーするのに費やされる時間が無駄であると認識されているため、これを行いません。低速で無駄の多いメモリ アクセスを伴うシングル コア マシンの場合。

ただし、QPI や Hypertransport などの最近の「メモリ アクセス」とは何かを考えると、そもそもデータを単にコピーすることとそれほど違いはありません。どちらの場合も、1 つのコアのメモリ コントローラーから別のコアのキャッシュにシリアル バス経由でデータが送信されます。

今日の CPU は、実際には NUMA マシンであり、SMP 環境を偽装するためにシリアル ネットワークの上にメモリ アクセス プロトコルが階層化されています。パイプやメッセージ キューなどを介してメッセージをコピーするスタイルのプログラミングは、間違いなく NUMA の考え方に満足しており、実際には SMP はまったく必要ないと言う方向に向かっています。

また、すべてのスレッド間通信をメッセージ キューとして行う場合、それらはパイプとあまり変わらず、パイプはネットワーク ソケットとそれほど違いはありません (少なくとも Windows 以外ではそうです)。そのため、コードを慎重に記述すれば、コンピュータの分散ネットワーク全体または単一プロセス内の多数のスレッド全体に再展開できるプログラムを作成できます。スケールアップしても、プログラムの形状や感触を大幅に変更しないため、これはスケーラビリティを実現するための優れた方法です。

フリンジベネフィット

使用するシリアライゼーション テクノロジによっては、付加的な利点がいくつかある場合があります。ASN.1 では、メッセージのコンテンツの有効な範囲を設定するメッセージ スキーマを指定します。たとえば、メッセージに整数が含まれており、0 から 10 の値を持つことができます。適切な ASN.1 ツールによって生成されたエンコーダーとデコーダーは、送信または受信しているデータがその制約を満たしていることを自動的にチェックします。 、そうでない場合はエラーを返します。

Google Protocol Buffers のような他のシリアライザーが同様の制約チェックを行わなかったとしたら、私は驚くでしょう。

利点は、プログラムにバグがあり、仕様外のメッセージを送信しようとした場合、シリアライザーが自動的にそれを検出することです。これにより、デバッグにかかる​​時間を大幅に節約できます。また、メモリ バッファを共有し、メッセージ キューを使用する代わりにセマフォで保護する場合、これは絶対に得られないことです。

CSP

シーケンシャル プロセスの通信とアクター モデルは、メッセージ キューやパイプなどを介してデータのコピーを送信することに基づいています。特に CSP は注意を払う価値があります。これは、ソース コードに潜んでいる可能性があるマルチスレッド ソフトウェアの多くの落とし穴を回避する優れた方法だからです。

そのまま使用できる CSP 実装がいくつかあります。Java 用のクラス ライブラリである JCSP と、C++ 用の CSP を実行するために Boost の上に構築された C++CSP があります。二人ともケント大学出身。

C++CSP は非常に興味深いものに見えます。これには csp::mobile という名前のテンプレート クラスがあり、Boost スマート ポインターのようなものです。これらのいずれかをあるスレッドから別のスレッドにチャネル (メッセージ キューに対する CSP の言葉) を介して送信すると、データではなく参照が送信されます。ただし、テンプレートは、どのスレッドがデータを「所有」しているかを記録します。そのため、モバイルを受信したスレッドはデータを所有し (実際には移動していません)、それを送信したスレッドはデータにアクセスできなくなります。したがって、データをコピーするオーバーヘッドなしで CSP の利点を得ることができます。

また、C++CSP は TCP 経由でチャネルを実行できるようです。これは非常に魅力的な機能で、アップスケーリングは非常に簡単な可能性です。JCSP はネットワーク接続でも機能します。

于 2013-10-24T21:13:09.253 に答える