C++ 中的低延迟回调
Low latency callback in C++
我有一个事件驱动的应用程序。我想保持事件处理程序(EventHandler
class 能够处理 many/all 事件)一个通用的实现 - 同时允许 EventSource
可变(特别是 - 在编译时)。
为了将 EventHandler
与 EventSource
相结合,我将不得不在 EventSource
中存储一个 handler 的实例。我尝试存储各种形式的 handlers:
- 指向
EventHandler
接口的指针(在具体 EventHandler
的 中定义了 public 处理程序方法
std::function
的实例 - 这提供了最大的灵活性
然而,在这两种情况下,调用目标 method/lambda 的延迟都非常高(在我的测试设置中约为 250ns)——更糟糕的是,不一致。可能是由于virtual table and/or heap allocation and/or type erasure ???
为了减少延迟,我想使用模板。
我能想到的最好的是:
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
都必须是模板 class。
问题是:这是实现一致且低延迟回调的最佳方式吗?是否可以改进此代码以避免事件源 class 完全独立于事件处理程序对象的类型?
Is this best way to achieve consistent and low latency to callback?
正如问题评论中所建议的那样,我宁愿 尝试并衡量 以了解这是否真的是一个问题,以及什么是最适合您的选择。
没有最好的方法,主要还是要看实际问题。
can this code be improved to avoid the event source classes be completely independent of event handler objects' type ?
也许以下内容可以作为开始实现该目标的一个很好的起点:
#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 上查看。
我有一个事件驱动的应用程序。我想保持事件处理程序(EventHandler
class 能够处理 many/all 事件)一个通用的实现 - 同时允许 EventSource
可变(特别是 - 在编译时)。
为了将 EventHandler
与 EventSource
相结合,我将不得不在 EventSource
中存储一个 handler 的实例。我尝试存储各种形式的 handlers:
- 指向
EventHandler
接口的指针(在具体EventHandler
的 中定义了 public 处理程序方法
std::function
的实例 - 这提供了最大的灵活性
然而,在这两种情况下,调用目标 method/lambda 的延迟都非常高(在我的测试设置中约为 250ns)——更糟糕的是,不一致。可能是由于virtual table and/or heap allocation and/or type erasure ???
为了减少延迟,我想使用模板。
我能想到的最好的是:
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
都必须是模板 class。
问题是:这是实现一致且低延迟回调的最佳方式吗?是否可以改进此代码以避免事件源 class 完全独立于事件处理程序对象的类型?
Is this best way to achieve consistent and low latency to callback?
正如问题评论中所建议的那样,我宁愿 尝试并衡量 以了解这是否真的是一个问题,以及什么是最适合您的选择。
没有最好的方法,主要还是要看实际问题。
can this code be improved to avoid the event source classes be completely independent of event handler objects' type ?
也许以下内容可以作为开始实现该目标的一个很好的起点:
#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 上查看。