3

C言語を使って様々な組み込み機器を制御するための小さなライブラリを作っています。各デバイスとの通信に UDP ソケットを使用しています。デバイスは、さまざまな興味深いデータ、アラーム、および通知を私に送信すると同時に、ライブラリによって内部的に使用されているが、ユーザーにとって興味深いものではない可能性のあるデータを送信します。そのため、コールバック アプローチを実装しました。ユーザーは、各デバイスでいくつかの興味深いイベントを使用してコールバック関数を登録できます。現在、このライブラリの全体的な設計は次のようになっています:-

  • 私は2つのスレッドを実行しています。
  • スレッドの 1 つに、各デバイスとの通信を維持するために使用する無限イベントループがありますwhileselectnon-blocking sockets
  • 基本的に、デバイスのいずれかからパケットを受信するたびに、20 バイトの役に立たない情報であるヘッダーを取り除き、(そのパケットを取得するために要求が送信された時刻と (パケットが実際に到着した時刻) を含む独自のヘッダーを追加DEVICE_IDREQUES_TIMEますRETRIEVAL_TIME。 ) およびREQUEST_ID(REQUEST_TYPEアラーム、データ、通知など)。
  • ここで、このスレッド (無限ループを持つスレッド) は、新しいヘッダーを持つパケットをリング バッファーに入れ、他のスレッド (スレッド #2) にこの情報を解析するよう通知します。
  • スレッド #2 では、通知を受信すると、バッファをロックし、パケットを読み取りポップして解析を開始します。
  • すべてのメッセージには、ユーザーが興味を持たない可能性のある情報が含まれているため、ユーザーにとって有用なデータに基づいて行動するためのユーザー コールバック アプローチを提供しています。

基本的に、私はスレッド2でこのようなことをしています:-

スレッド #2

wait(data_put_in_buffer_cond)

lock(buffer_mutex)

packet_t* packet = pop_packet_from_buffer(buf);

unlock(buffer_mutex)

/* parsing the package... */
parsed_packet_t* parsed_packet = parse_and_change_endianess(packet->data);
/* header for put by thread #1 with host byte order only not parsing necessary */
header_t* header = get_header(packet);

/* thread 1 sets free callback for kind of packet it puts in buffer 
 * This not a critical section section of buffer, so fine without locks
 */
buffer.free_callback(packet);

foreach attribute in parsed_packet->attribute_list {
   register_info_t* rinfo = USER_REGISTRED_EVENT_TABLE[header->device_id][attribute.attr_id];

   /*user is register with this attribute ID on this device ID */
   if(rinfo != NULL) {
      rinof->callback(packet);
   }

   // Do some other stuff with this attribute..
}
free(parsed_packet);

さて、私の懸念は、ユーザーが実装するコールバック関数が完了するまでに時間がかかり、その間にリング バッファーが上書きモードになっているために一部のパケットをドロップする可能性がある場合にどうなるかということです。3 ~ 4 台のデバイスで API をテストしましたが、コールバック関数が適切な時間待機する場合、ドロップ イベントはあまり見られません。このアプローチは最適ではない可能性があると推測しています。

ある種のスレッドプールを使用してユーザーのコールバック関数を実行すると、より良い設計になりますか? その場合、ユーザーのコールバックに送信する前に、パケットの明示的なコピーを作成する必要がありますか? 各パケットは約 500 ~ 700 バイトで、各デバイスから 1 秒あたり約 2 パケットを取得します。現在の設計の改善またはこの問題の解決に関する提案やコメントをいただければ幸いです。

4

1 に答える 1

1

デバイスごとに 500 ~ 700 バイトを取得することは、特に 3 ~ 4 個のデバイスしかない場合はまったく問題ありません。たとえば、100 台のデバイスがあったとしても、問題にはなりません。コピーのオーバーヘッドはおそらく無視できる程度です。したがって、私の提案は次のとおりです。バッファーのコピーがボトルネックであることが確実になるまで、事前に最適化を試みないでください。

あなたの質問で言うように、パケットの損失については、すでにバッファリングを使用しています(循環キューのようなものだと思いますよね?)。キューがいっぱいになった場合は、キューに使用可能なスペースができるまでスレッド #1 を待機させる必要があります。明らかに、さまざまなデバイスからさらに多くのイベントが到着する可能性がありますが、それは問題ではありません。スペースが再び確保されるselectと、さまざまなデバイスから利用可能なデータがあることが通知されるため、そのすべてのデータを処理するだけで済みます。もちろん、バランスの取れたシステムにするために、キューがいっぱいになる回数をできる限り減らす値にキューのサイズを設定できます。したがって、スレッド #1 は待機する必要があります。

于 2012-05-28T09:30:39.247 に答える