1

2 つのライブラリ (A と B) があり、それぞれにソケットをリッスンする関数が 1 つあるとします。これらの関数は select() を使用し、データが到着した場合はすぐに何らかのイベントを返します。それ以外の場合は、しばらく ( timeout ) 待ってから NULL を返します。

A_event_t* A_wait_for_event(int timeout);
B_event_t* B_wait_for_event(int timeout); 

今、私は自分のプログラムでそれらを使用しています:

int main (int argc, char *argv[]) {
// Init A
// Init B
// .. do some other initialization
    A_event_t *evA;
    B_event_t *evB;
    for(;;) {
        evA = A_wait_for_event(50);
        evB = B_wait_for_event(50);
        // do some work based on events
    }
}

各ライブラリには独自のソケット (udp ソケットなど) があり、外部からアクセスすることはできません。

問題: これはあまり効率的ではありません。たとえば、*B_wait_for_event* によって配信されるのを待っているイベントがたくさんある場合、これらは *A_wait_for_event* タイムアウトまで常に待機する必要があり、ライブラリ B と私のプログラムのスループットが効果的に制限されます。

通常、スレッドを使用して処理を分離できますが、イベントの処理で他のライブラリの関数を呼び出す必要がある場合や、その逆の場合はどうでしょう。例:

if (evA != 0 && evA == A_EVENT_1) {
    B_do_something();
}
if (evB != 0 && evB == B_EVENT_C) {
    A_do_something();
}

したがって、2 つのスレッドを作成してライブラリから機能を分離できたとしても、これらのスレッドはそれらの間で (おそらくパイプを介して) イベントを交換する必要があります。1 つのスレッドが *X_wait_for_event()* 関数によってブロックされ、他のスレッドからすぐにデータを受信できないため、これでもパフォーマンスが制限されます。

これを解決するには?

4

3 に答える 3

3

使用しているライブラリによっては、この解決策を利用できない場合がありますが、最善の解決策は、イベントを待機する個々のライブラリで関数を呼び出さないことです。各ライブラリは、外部イベント ループへのフックをサポートする必要があります。次に、アプリケーションは、使用するすべてのライブラリが待機するすべてのイベントを待機するpoll()or呼び出しを含む単一のループを使用します。select()

glib のイベント ループはこれに適しています。これは、多くのライブラリが既にそれにフックする方法を知っているためです。しかし、glib ほど精巧なものを使用しない場合、通常のアプローチは次のとおりです。

  • 永遠にループ:
    • 無限タイマーと空のファイル記述子セットから開始します
    • 使用するライブラリごとに:
      • ファイル記述子をセットに追加したり、タイムアウトを短縮したり (長くはしない) することが許可されているライブラリのセットアップ関数を呼び出します。
    • 走るpoll()
    • 使用するライブラリごとに:
      • poll()が返されたときに発生した可能性のあるイベントに応答する、ライブラリ内のディスパッチ関数を呼び出します。

はい、以前のライブラリが後のライブラリを枯渇させる可能性は依然としてありますが、実際には機能します。

使用しているライブラリがこの種のセットアップおよびディスパッチ インターフェイスをサポートしていない場合は、それを機能として追加し、コードをアップストリームに投稿してください!

于 2012-04-04T14:38:41.187 に答える
2

(コメントするには長すぎるため、これを回答に移動しています)

A_do_something別のスレッドの実行中に別のスレッドを呼び出すことが許可されていない状況にある場合A_wait_for_event(および同様に)、効率的なことは何もできずB、さまざまな悪の間で解決する必要があると確信しています。

最も明らかな改善点は、両方から読み取ろうとするのではなく、イベントを取得するとすぐにアクションを実行することです。つまり、ループを順序付けます

  • A イベントを待つ
  • 多分Bで何かをする
  • Bイベント待ち
  • 多分Aで何かをする

あなたができる他の軽減策は次のとおりです

  • A イベントと B イベントのどちらが次に発生する可能性が高いかを予測して、最初にそれを待ちます。(たとえば、連続して発生する場合は、A イベントを取得して処理した後、別の A イベントの待機に戻る必要があります)
  • タイムアウト値をいじって、スピン ループと過度のブロッキングとのバランスをとります。(おそらく動的に調整することさえあります)

編集: ライブラリの API を確認してください。彼らはすでに問題に対処する方法を提供しているかもしれません。たとえば、イベントのコールバックを登録し、ポーリングではなくコールバックを介してイベントの通知を取得できる場合がありますwait_for_event

別のことは、ライブラリがリッスンするための新しいファイル記述子を作成できるかどうかです。たとえば、新しいパイプを作成し、一方の端を libraryAに渡した場合、スレッド #1 がイベントを待機しているA場合、スレッド #2 はパイプに書き込みを行ってイベントを発生させることができるため、#1 は から強制的に除外されwait_for_eventます。関数からスレッドを自由に追い出すwait_for_event機能により、あらゆる種類の新しいオプションが利用可能になります。

于 2012-04-04T14:22:37.487 に答える
1

可能な解決策は、「何かを行う」「メイン」スレッドにwait_for_eventsプラスするために2つのスレッドを使用することです。boost::condition_variable似ているが正確ではない解決策がここにあります

于 2012-04-04T14:21:23.083 に答える