5

UDP を使用して他のピアに音声を送信する c++ を使用して、p2p アプリケーションを設計しています。

ループ内で 1 秒間音声をキャプチャするスレッド内のバッファでマイク信号をキャプチャしています。バッファにキャプチャされた 2 番目の音声ごとwhileに、それをパケットに分割し、他のピアに送信します。ここで、リアルタイム伝送に対応する宛先での適切なデータ構造が必要です。スクリーン キャプチャに使用するのと同じデータ構造です。私が考えたキューを使用した2つのアプローチを次に示します

  • OneSecVoiceオブジェクトまたは画像の場合はオブジェクトのキューを維持するリンク リストを使用してキューを実装しますImage

  • OneSecVoiceまたはImageオブジェクトの静的配列を使用したキューの実装

OneSecVoice/Imageオブジェクトには、パケットの総数、その特定のパケットバッファImage/OneSecVoiceが含まれます。

リアルタイムであるため、1 つのスレッドが継続的にキューをスキャンし、キューからポップすることで最新の完全なものを取り出し ます。Image/OneSecVoiceImage/OneSecVoice

したがって、リンクされたリストを使用してキューを実装するか、静的配列を使用してキューを実装するかを選択します。

私と私の友人はこれをめぐって争っているので、ここに投稿することにしました.

4

4 に答える 4

5

boost::circular_bufferを使用します。固定メモリ領域があり、予期しないメモリ割り当てがないため、キャッシュの利点が得られます。

最大の効率を達成するために、circular_buffer はその要素をメモリの連続した領域に格納します。これにより、以下が可能になります。

  1. 固定メモリを使用し、暗黙的または予期しないメモリ割り当てを行わない。
  2. 表裏から素早い一定時間の挿抜が可能。
  3. 要素への一定時間の高速ランダム アクセス。
  4. リアルタイムおよびパフォーマンスが重要なアプリケーションへの適合性。

circle_buffer の可能な用途は次のとおりです。

  • 最近受信したサンプルを保存し、新しいサンプルが到着すると最も古いものを上書きします。
  • バウンド バッファーの基になるコンテナーとして (バウンド バッファーの例を参照してください)。
  • 指定された数の最後に挿入された要素を格納する一種のキャッシュ。
  • 効率的な固定容量の FIFO (先入れ先出し) または LIFO (後入れ先出し) キューは、いっぱいになると最も古い (最初に挿入された) 要素を削除します。
于 2009-10-11T18:46:18.143 に答える
3

どちらも実装しないでください。標準ライブラリの既存の実装を使用します。

std::queue<T, std::list<T> >
std::queue<T, std::deque<T> > // uses deque by default, by the way

これらを型定義して、2 つを簡単に入れ替えることができます。

template <typename T>
struct queue_list
{
    typedef typename std::queue<T, std::list<T> > value_type;
}

template <typename T>
struct queue_array
{
    typedef typename std::queue<T, std::deque<T> > value_type;
}

typedef queue_list<the_type>::value_type container_type; // use one
typedef queue_array<the_type>::value_type container_type;

今すぐプロファイリングして、どちらが優れているかを見つけてください。キャッシュに関しては、アレイのパフォーマンスが向上する可能性があります。

ブーストのプール アロケータを使用して、配列のキャッシュ パフォーマンスと共に、リストの迅速な挿入と削除の利点を得ることができます。

typedef typename std::queue<T, std::list<T, boost::pool_allocator<T> > > value_type;

fnieto で提案されboost::circular_bufferているように、試す別の構造は次のとおりです。

template <typename T>
struct queue_buffer
{
    typedef typename std::queue<T, boost::circular_buffer<T> > value_type;
}    
于 2009-10-11T18:30:28.083 に答える
1

受信側での唯一の操作がキューからポップすることである場合、静的配列を使用する意味がよくわかりません。これは、連続したデータのチャンクを操作する必要がある場合や、ランダムアクセスの場合に一般的に役立ちます。

静的配列を使用してもスペースを節約できるとは思いません。確かに、エントリごとにポインターを保存していますが、メモリの大きな固定ブロックを割り当てるという犠牲を払っています。また、キューが時々大きくなる場合は、任意のサイズに大きくなる可能性があるため、リンクされたリストによって提供される柔軟性が必要になる場合があります。

拡張できるサイズを制限したい場合は、どちらのスキームでもそれを行うことができます。

于 2009-10-11T18:32:50.230 に答える
0

リンクされたリストは標準的なアプローチになります.「静的配列を使用してキューを実装する」は、実際に私がそれを行う方法です.udpパケットを再構築するために、おそらく順序付けられたデータをLLに渡します。udpが予期しないシーケンスで来る可能性があるため、そこに詰め込むことはできないため、「キューを継続的にスキャンして最新の完全なものを取り出す」をどのように踊るつもりですか。最新の完全版は、「Coffee」が「Beans type:」の後に来るという意味ではありません。

于 2009-10-11T19:00:55.587 に答える