У меня есть приложение, управляемое событиями. Я хочу сохранить обработчик события (EventHandler
класс, способный ко многим/всем событиям), общую реализацию - при этом можно изменить переменную EventSource
(в частности - во время компиляции).Обратный вызов с низкой задержкой в C++
Для соедини EventHandler
с EventSource
, я должен хранить экземпляр обработчика в EventSource
. Я пытался хранить обработчиков различных форм:
- указатель на интерфейс
EventHandler
(то есть публичные методы обработчиков, определенные в конкретномEventHandler
«ы - экземпляр
std::function
- это обеспечило большую гибкость
Однако в обоих случаях задержка при вызове целевого метода/лямбда была довольно высокой (на моей тестовой установке около 250 нс) - и, что еще хуже, была непоследовательной. Может быть, из-за размещения виртуальной таблицы и/или кучи и/или стирание типа
Чтобы уменьшить эту задержку, я хочу использовать шаблоны.
Лучшее, что я мог придумать это:
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
«s, чтобы быть шаблоном класса.
Вопрос: Это лучший способ добиться последовательной и низкой задержки для обратного вызова? Можно ли улучшить этот код, чтобы избежать того, чтобы исходные классы событий полностью не зависели от типа объектов обработчика событий?
Вы пробовали, что такое латентность, если - только для диагностической цели - вы называете одного хорошо известного обработчика событий из одного хорошо известного источника событий через статически связанную функцию? Просто, чтобы узнать, действительно ли вызвана латентность вызовом, и какие-либо другие эффекты не применяются (например, объекты, которые должны быть созданы, код диспетчера для оценки, потоки, которые блокируют друг друга или что-то еще)? –
Сначала попытайтесь измерить простой неприкрашенный указатель на регулярную функцию, отличную от члена. Не может превзойти это. Если вы считаете, что его эффективность приемлема, у вас есть шанс на бой. Виртуальный вызов должен иметь, по существу, ту же производительность, что и указатель на функцию. Прошли ли вы какие-либо реальные профилирования? –
@StephanLechner, хорошо известная функция-член хорошо известного объекта принимает <30ns последовательно. Виртуальный вызов занимает примерно 60 нс, но остается неизменным. Любое из этого является приемлемым (поскольку они являются согласованными). Я получаю подобное поведение с вышеуказанным кодом с шаблоном. p.s. Я не делал никакого профилирования. – rat6