3

最初に、私がやろうとしていることについて少し説明します。

私の計画は、boost:spirit::qi を使用して実装されたパーサーにデータを供給する、boost::asio ライブラリを使用して実装されたソケット ストリームを持つプログラムを作成することです。パーサーはパケットを受け取り、パケット オブジェクトを埋めてから、そのオブジェクトをパケット オブジェクトのリンク リストの末尾に追加します。パケット プロセッサは、リスト内の最初のオブジェクトを読み取り、その処理を実行してから、次の項目に移動して最初のオブジェクトを削除します。

リンク リストを使用することにしたのは、std::queue を使用した場合、ストリームがパケットを追加するたびに、またはプロセッサがパケットを削除するたびにコンテナー全体をロックする必要があり、2 つのスレッドが多かれ少なかれ連続して実行されるためです。避けたいと思います。さらに、キュー クラスにはオブジェクト全体をコピーする傾向がありますが、リンク リストのアイデアには、オブジェクトを一度作成してからそれを指すだけでよいという利点があります。このビジネス全体のシリアライズを避けるために、boost:mutex ミューテックスを各ノードに配置し、そこからロックするつもりです。アイデアは、ソケット ストリームでリストを作成し、すぐに最初のノードをロックし、パーサーからノードに入力し、次のノードを作成してロックし、最初のノードのロックを解除して次のノードに移動して作業を行うことです。こっちへ」ソケット ストリーム ノーズの下でパケット プロセッサがジャンプして削除する可能性がある、ロックされていないノードが最後にぶら下がることは決してありません。パケット プロセッサは最初のノードをチェックしてロックしようとします。ロックされている場合は、処理を行ってからロックを解除し、次のノードを取得して最初のノードを削除します。このように、シリアライゼーションは、パケット プロセッサがソケット ストリーム クラスに追いついた時点に限定されます。

さて、私の質問は、これを実際に実装する作業を行う前に、これは良いアイデアのように聞こえますか? 簡単なテストで試してみましたが、問題なく動作するようです。例外処理を実装し、割り当てたメモリを解放するように注意している限り、これに関する重大な問題は考えられませんが、誰かが考えられる場合私が見落としていたこのアイデアに関する問題があれば、ご意見をいただければ幸いです。また、代替案として、またはこのアイデアをよりうまく機能させる可能性のある他の提案をいただければ幸いです。

前もって感謝します!

4

5 に答える 5

2

この記事を確認してください。これは複数の消費者に関するものですが、それでも素晴らしいです:

並列パフォーマンスの測定: 同時キューの最適化

于 2011-07-02T14:50:18.410 に答える
0

これを連結リストと呼んでいますが、実際にはこれはキューです。

固定サイズのバッファを使用したい場合は、Single Producer Single Consumer のロックフリー キューを実装することができます。これにより、コンシューマーの速度が十分でない場合にプロデューサーを待機させることを犠牲にして、メモリ使用量を制御できます。

このわずかな点を除けば、あなたのデザインは見栄えがします。おそらく、ロックフリーの代替手段よりも正しく取得する方が簡単です。

nextProducer が Consumer に、これ以上処理するものがないことを通知できるように、終了条件 (たとえば、フィールド内のヌル ポインター) を用意することを忘れないでください。

于 2011-07-02T15:02:17.170 に答える
0

この実装は私に 3 つのことを叫んでいます。

  • 挿入と削除では複数のミューテックスを同時にロックする必要があり、同時にそれを行うことはできないため、デッドロックが発生しやすい方法です。できますが、ミューテックスの周りにミューテックスを配置する必要があります。
  • あまりにも簡単に破損します。デッドロックにつながる問題は、破損にもつながる可能性があります。
  • そしてゆっくり、ゆっくり、ゆっくり。リストウォーカーのことを考えてみてください。各ステップには、ロック解除、ロック、別のロック解除、および別のロックが含まれます。足踏みには非常に注意する必要があり、費用がかかります。各アイテムを正しい順序でロックおよびロック解除しますか? ああ。

これは、時期尚早の最適化と時期尚早の悲観化が並行して行われているケースのように見えます。このアーキテクチャの原動力は何ですか?

最初は簡単な解決策から始めることをお勧めします。その一部に触れたいときはいつでも全体をロックしてください。それがあなたを困らせるかどうか見てください。そうでない場合、問題は解決しました。そうであれば、次のステップはミューテックスから読み書きロックに切り替えることです。数兆個ではなく、1個だけです。ここで、共有ロックと排他ロックのどちらが必要かについて少し考える必要があります。const の正確性について熱心に取り組んできた場合は、const メソッドには共有ロック (読み取りロック) を、非 const メソッドには排他ロック (書き込みロック) を使用してみてください。

于 2011-07-02T15:11:19.840 に答える
0

あなたが提案したことはうまくいかないと思います。リンクされたリストからノードを削除するときは、削除されたノードを指す他のノードを更新する必要があることに注意してください。同様に、ノードを追加するときは、新しいノードを指すように他のノードも更新する必要があります。したがって、削除または追加されるノードをロックするだけでは十分ではありません。

ロックフリーのキューはありますが、正しく取得するのは非常に困難です。たとえば、公開されたアルゴリズムを機能させるために必要な追加作業について説明している記事への最初のコメントを見てください。

于 2011-07-02T14:51:50.763 に答える
0

うーん.. よくある問題に対して、なぜこれほど複雑な解決策が必要なのでしょうか? そこにはたくさんのプロデューサー/コンシューマー キュー クラスがあります - 動作するリファレンス/ポインター/整数サイズのものを選んでください (つまり、データのコピーはありません)。

プロトコルに従って「パケット オブジェクト」を組み立てるまで、ストリームからバイトを取得します。パケット オブジェクト参照をキューに押し込み、すぐに次のパケットのために別の参照を new() します。パケット プロセッサは、キューからパケット オブジェクトを消費します。

キューは、オブジェクト参照をキューにプッシュ/ポップするのにかかる時間だけロックされます。ソケット/ストリーム コールバックによって組み立てられるパケット オブジェクトと、パケット プロセッサによって処理されるパケット オブジェクトは常に異なるため、ロックは必要ありません。

すでにキュー (またはキューのようなリンク リスト) にあるオブジェクトを操作しようとすることは、私には悪夢のように思えます (他の投稿者も同意しているようです)。これを行う必要がある他の理由はありますか?

Rgds、マーティン

于 2011-07-02T16:16:23.913 に答える