2017-02-07 3 views
4

私はイベント駆動型アプリケーションを持っています。 EventSourceが( - コンパイル時に特異的に)変更すること可能にしながら - 私は、イベントハンドラ(多くの/すべてのイベントの可能EventHandlerクラス)一般的な実装を維持したいです。カップルへC++での待ち時間の短いコールバック

EventSourceEventHandler、私はEventSourceハンドラのインスタンスを格納する必要があります。私は、ハンドラ様々な形態のを格納しようとした:EventHandlerの界面に

  • ポインタ(すなわち、コンクリートで定義されたパブリック・ハンドラメソッドを有するEventHandlerstd::function
  • インスタンス - これは最大の柔軟性
を提供しました

しかし、どちらの場合も、ターゲットメソッド/ラムダを呼び出す際の待ち時間が(約250ns私のテスト・セットアップに)かなり高かった - と悪いことに、矛盾した仮想テーブルおよび/またはヒープ割り当てが原因である可能性があり、および/または。タイプ消去?

この待ち時間を短縮するために、私は、テンプレートを利用することにしたいです。

私が思い付くことができる最高は次のとおりです。

template <typename EventHandler> 
class EventSource1 
{ 
    EventHandler* mHandler; 
public: 
    typedef EventHandler EventHandlerType; 

    void AssignHandler (EventHandler* handler) 
    { 
     this->mHandler = handler; 
    } 

    void EventuallyDoCallback (int arbArg) 
    { 
     this->mHandler->CallbackFunction (arbArg); 
    } 
}; 

template <EventSourceType> 
class EventSourceTraits 
{ 
    typedef EventSourceType::EventHandlerType EventHandlerType; 
    static void AssignHandler (EventSourceType& source, EventHandlerType* handler) 
    { 
     source.AssignHandler(handler); 
    } 
}; 

class EventHandler 
{ 
public: 
    void CallbackFunction (int arg) 
    { 
     std::cout << "My callback called\n"; 
    } 
}; 


int main() 
{ 
    EventSource1<EventHandler> source;     /// as one can notice, EventSource's need not to know the event handler objects. 
    EventHandler handler; 

    EventSourceTraits<EventSource1>::AssignHandler (source, &handler); 
} 

このメソッドは、すべて私のEventSource年代は、テンプレートクラスなるように制限を課します。

質問::コールバックに一貫性のある低遅延を実現するための最良の方法はありますか?このコードを改善して、イベントソースクラスがイベントハンドラオブジェクトの型から完全に独立しないようにすることはできますか?

+1

あなたは待ち時間があれば何であるか試してみたことがありますか?待ち時間が実際に呼び出され、他のエフェクトが適用されないかどうか(例:インスタンス化されるオブジェクト、評価するディスパッチャコード、お互いにロックするスレッド、またはこれまでのものなど)を調べるだけです。 –

+3

通常のメンバではない関数への単純な未使用のポインタを最初に試してみてください。それを上回ることはできません。あなたがそのパフォーマンスを受け入れることがわかったら、あなたは戦うチャンスがあります。仮想呼び出しは、本質的に関数ポインタと同じ性能を持つはずです。あなたは本当のプロファイリングをしましたか? –

+0

@StephanLechnerは、良く知られているオブジェクトのよく知られているメンバ関数です。一貫して<30nsを要します。 仮想通話には約60nsかかりますが、一貫しています。 どちらも一致していてもかまいません。私はテンプレートで上記のコードと同様の動作を取得します。 p.s.私はどんな種類のプロファイリングもしていない。 – rat6

答えて

1

はcallbackに一貫して低遅延を実現するために、この最善の方法ですか?質問へのコメントで示唆したように

、私はむしろ試してみた、それは本当に問題だと何のための最善の選択肢だかどうかを知るためにを測定します。
最善の方法が存在していない、それは主に実際の問題に依存します。

このコードを改善して、イベントソースクラスがイベントハンドラオブジェクトの型から完全に独立しないようにすることはできますか?

たぶん、次はそれを達成するために開始するには、そこから良い点になります

#include <iostream> 

class EventSource1 
{ 
    using invoke_t = void(*)(void *C, int value); 

    template<typename T, void(T::*M)(int)> 
    static void proto(void *C, int value) { 
     (static_cast<T*>(C)->*M)(value); 
    } 

    invoke_t invoke; 
    void *handler; 

public: 
    template<typename T, void(T::*M)(int) = &T::CallbackFunction> 
    void AssignHandler (T* ref) 
    { 
     invoke = &proto<T, M>; 
     handler = ref; 
    } 

    void EventuallyDoCallback (int arg) 
    { 
     invoke(handler, arg); 
    } 
}; 

class EventHandler 
{ 
public: 
    void CallbackFunction (int arg) 
    { 
     std::cout << "My callback called: " << arg << std::endl; 
    } 
}; 

int main() 
{ 
    EventSource1 source; 
    EventHandler handler; 

    source.AssignHandler(&handler); 
    source.EventuallyDoCallback(42); 
} 

wandboxでそれを参照してください。ただ、診断目的のために - - あなたは静的にバインドされた関数を使用して1つのよく知らイベントソースから1つのよく知られてイベントハンドラを呼び出す

+1

私が書いている低レイテンシのプログラムでは、私は仮想関数のレイテンシに匹敵する解決策を期待していました。 あなたのテンプレートを使用したソリューションは、私にはうってつけです。ありがとうございました ! – rat6

+0

@ rat6大歓迎です。 ;-) – skypjack

関連する問題