any simple and fast call back mechanism? - c++

i am implmenting an event-driven message processing logic for a speed-sensitive application. I have various business logics which wrapped into a lot of Reactor classes:
class TwitterSentimentReactor{
on_new_post(PostEvent&);
on_new_comment(CommentEvent&);
};
class FacebookSentimentReactor{
on_new_post(PostEvent&);
on_new_comment(CommentEvent&);
};
class YoutubeSentimentReactor{
on_new_post(PostEvent&);
on_new_comment(CommentEvent&);
on_new_plus_one(PlusOneEvent&);
};
let's say, there are 8 such event types, each Reactor respond to a subset of them.
the core program has 8 'entry point' for the message, which hooked up with some low-level socket processing library, for instance
on_new_post(PostEvent& pe){
youtube_sentiment_reactor_instance->on_new_post(pe);
twitter_sentiment_reactor_instance->on_new_post(pe);
youtube_sentiment_reactor_instance->on_new_post(pe);
}
I am thinking about using std::function and std::bind, to build a std::vector<std::function<>>, then I loop through the vector to call each call-back function.
However, when I tried it,std::function proved to not be fast enough. Is there a fast yet simple solution here? As i mentioned earlier, this is VERY speed sensitive, so i want to avoid using virtual function and inheritance, to cut the v-table look up
comments are welcomed. thanks

I think that in your case it is easier to do an interface, as you know are going to call simple member functions that match exactly the expected parameters:
struct IReactor {
virtual void on_new_post(PostEvent&) =0;
virtual void on_new_comment(CommentEvent&) =0;
virtual void on_new_plus_one(PlusOneEvent&) =0;
};
And then make each of your classes inherit and implement this interface.
You can have a simple std::vector<IReactor*> to manage the callbacks.
And remember that in C++, interfaces are just ordinary classes, so you can even write default implementations for some or all of the functions:
struct IReactor {
virtual void on_new_post(PostEvent&) {}
virtual void on_new_comment(CommentEvent&) {}
virtual void on_new_plus_one(PlusOneEvent&) {}
};

std::function main performance issue is that whenever you need to store some context (such as bound arguments, or the state of a lambda) then memory is required which often translates into a memory allocation. Also, the current library implementations that exist may not have been optimized to avoid this memory allocation.
That being said:
is it too slow ? you will have to measure it for yourself, in your context
are there alternatives ? yes, plenty!
As an example, what don't you use a base class Reactor which has all the required callbacks defined (doing nothing by default), and then derive from it to implement the required behavior ? You could then easily have a std::vector<std::unique_ptr<Reactor>> to iterate over!
Also, depending on whether the reactors need state (or not) you may gain a lot by avoiding allocating objects from then and use just functions instead.
It really, really, depends on the specific constraints of your projects.

If you need fast delegates and event system take a look to Offirmo:
It is as fast as the "Fastest possible delegates", but it has 2 major advantages:
1) it is ready and well tested library (don't need to write your own library from an article)
2) Does not relies on compiler hacks (fully compliant to C++ standard)
https://github.com/Offirmo/impossibly-fast-delegates
If you need a managed signal/slot system I have developed my own(c++11 only).
It is not fast as Offirmo, but is fast enough for any real scenario, most important is order of magnitude faster than Qt or Boost signals and is simple to use.
Signal is responsible for firing events.
Slots are responsible for holding callbacks.
Connect how many Slots as you wish to a Signal.
Don't warry about lifetime (everything autodisconnect)
Performance considerations:
The overhead for a std::function is quite low (and improving with every compiler release). Actually is just a bit slower than a regular function call. My own signal/slot library, is capable of 250 millions(I measured the pure overhead) callbacks/second on a 2Ghz processor and is using std::function.
Since your code has to do with network stuff you should mind that your main bottleneck will be the sockets.
The second bottleneck is latency of instruction cache. It does not matter if you use Offirmo (few assembly instructions), or std::function. Most of the time is spent by fetchin instructions from L1 cache. The best optimization is to keep all callbacks code compiled in the same translation unit (same .cpp file) and possibly in the same order in wich callbacks are called (or mostly the same order), after you do that you'll see only a very tiny improvement using Offirmo (seriously, you CAN'T BE faster than Offirmo) over std::function.
Keep in mind that any function doing something really usefull would be at least few dozens instructions (especially if dealing with sockets: you'll have to wait completion of system calls and processor context switch..) so the overhead of the callback system will be neglictible.

I can't comment on the actual speed of the method that you are using, other than to say:
Premature optimization does not usually give you what you expect.
You should measure the performance contribution before you start slicing and dicing. If you know it won't work before hand, then you can search now for something better or go "suboptimal" for now but encapsulate it so it can be replaced.
If you are looking for a general event system that does not use std::function (but does use virtual methods), you can try this one:
Notifier.h
/*
The Notifier is a singleton implementation of the Subject/Observer design
pattern. Any class/instance which wishes to participate as an observer
of an event can derive from the Notified base class and register itself
with the Notiifer for enumerated events.
Notifier derived classes implement variants of the Notify function:
bool Notify(const NOTIFIED_EVENT_TYPE_T& event, variants ....)
There are many variants possible. Register for the message
and create the interface to receive the data you expect from
it (for type safety).
All the variants return true if they process the event, and false
if they do not. Returning false will be considered an exception/
assertion condition in debug builds.
Classes derived from Notified do not need to deregister (though it may
be a good idea to do so) as the base class destrctor will attempt to
remove itself from the Notifier system automatically.
The event type is an enumeration and not a string as it is in many
"generic" notification systems. In practical use, this is for a closed
application where the messages will be known at compile time. This allows
us to increase the speed of the delivery by NOT having a
dictionary keyed lookup mechanism. Some loss of generality is implied
by this.
This class/system is NOT thread safe, but could be made so with some
mutex wrappers. It is safe to call Attach/Detach as a consequence
of calling Notify(...).
*/
/* This is the base class for anything that can receive notifications.
*/
typedef enum
{
NE_MIN = 0,
NE_SETTINGS_CHANGED,
NE_UPDATE_COUNTDOWN,
NE_UDPATE_MESSAGE,
NE_RESTORE_FROM_BACKGROUND,
NE_MAX,
} NOTIFIED_EVENT_TYPE_T;
class Notified
{
public:
virtual bool Notify(NOTIFIED_EVENT_TYPE_T eventType, const uint32& value)
{ return false; };
virtual bool Notify(NOTIFIED_EVENT_TYPE_T eventType, const bool& value)
{ return false; };
virtual bool Notify(NOTIFIED_EVENT_TYPE_T eventType, const string& value)
{ return false; };
virtual bool Notify(NOTIFIED_EVENT_TYPE_T eventType, const double& value)
{ return false; };
virtual ~Notified();
};
class Notifier : public SingletonDynamic<Notifier>
{
public:
private:
typedef vector<NOTIFIED_EVENT_TYPE_T> NOTIFIED_EVENT_TYPE_VECTOR_T;
typedef map<Notified*,NOTIFIED_EVENT_TYPE_VECTOR_T> NOTIFIED_MAP_T;
typedef map<Notified*,NOTIFIED_EVENT_TYPE_VECTOR_T>::iterator NOTIFIED_MAP_ITER_T;
typedef vector<Notified*> NOTIFIED_VECTOR_T;
typedef vector<NOTIFIED_VECTOR_T> NOTIFIED_VECTOR_VECTOR_T;
NOTIFIED_MAP_T _notifiedMap;
NOTIFIED_VECTOR_VECTOR_T _notifiedVector;
NOTIFIED_MAP_ITER_T _mapIter;
// This vector keeps a temporary list of observers that have completely
// detached since the current "Notify(...)" operation began. This is
// to handle the problem where a Notified instance has called Detach(...)
// because of a Notify(...) call. The removed instance could be a dead
// pointer, so don't try to talk to it.
vector<Notified*> _detached;
int32 _notifyDepth;
void RemoveEvent(NOTIFIED_EVENT_TYPE_VECTOR_T& orgEventTypes, NOTIFIED_EVENT_TYPE_T eventType);
void RemoveNotified(NOTIFIED_VECTOR_T& orgNotified, Notified* observer);
public:
virtual void Reset();
virtual bool Init() { Reset(); return true; }
virtual void Shutdown() { Reset(); }
void Attach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
// Detach for a specific event
void Detach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
// Detach for ALL events
void Detach(Notified* observer);
// This template function (defined in the header file) allows you to
// add interfaces to Notified easily and call them as needed. Variants
// will be generated at compile time by this template.
template <typename T>
bool Notify(NOTIFIED_EVENT_TYPE_T eventType, const T& value)
{
if(eventType < NE_MIN || eventType >= NE_MAX)
{
throw std::out_of_range("eventType out of range");
}
// Keep a copy of the list. If it changes while iterating over it because of a
// deletion, we may miss an object to update. Instead, we keep track of Detach(...)
// calls during the Notify(...) cycle and ignore anything detached because it may
// have been deleted.
NOTIFIED_VECTOR_T notified = _notifiedVector[eventType];
// If a call to Notify leads to a call to Notify, we need to keep track of
// the depth so that we can clear the detached list when we get to the end
// of the chain of Notify calls.
_notifyDepth++;
// Loop over all the observers for this event.
// NOTE that the the size of the notified vector may change if
// a call to Notify(...) adds/removes observers. This should not be a
// problem because the list is a simple vector.
bool result = true;
for(int idx = 0; idx < notified.size(); idx++)
{
Notified* observer = notified[idx];
if(_detached.size() > 0)
{ // Instead of doing the search for all cases, let's try to speed it up a little
// by only doing the search if more than one observer dropped off during the call.
// This may be overkill or unnecessary optimization.
switch(_detached.size())
{
case 0:
break;
case 1:
if(_detached[0] == observer)
continue;
break;
default:
if(std::find(_detached.begin(), _detached.end(), observer) != _detached.end())
continue;
break;
}
}
result = result && observer->Notify(eventType,value);
assert(result == true);
}
// Decrement this each time we exit.
_notifyDepth--;
if(_notifyDepth == 0 && _detached.size() > 0)
{ // We reached the end of the Notify call chain. Remove the temporary list
// of anything that detached while we were Notifying.
_detached.clear();
}
assert(_notifyDepth >= 0);
return result;
}
/* Used for CPPUnit. Could create a Mock...maybe...but this seems
* like it will get the job done with minimal fuss. For now.
*/
// Return all events that this object is registered for.
vector<NOTIFIED_EVENT_TYPE_T> GetEvents(Notified* observer);
// Return all objects registered for this event.
vector<Notified*> GetNotified(NOTIFIED_EVENT_TYPE_T event);
};
Notifier.cpp
#include "Notifier.h"
void Notifier::Reset()
{
_notifiedMap.clear();
_notifiedVector.clear();
_notifiedVector.resize(NE_MAX);
_detached.clear();
_notifyDepth = 0;
}
void Notifier::Attach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType)
{
if(observer == NULL)
{
throw std::out_of_range("observer == NULL");
}
if(eventType < NE_MIN || eventType >= NE_MAX)
{
throw std::out_of_range("eventType out of range");
}
_mapIter = _notifiedMap.find(observer);
if(_mapIter == _notifiedMap.end())
{ // Registering for the first time.
NOTIFIED_EVENT_TYPE_VECTOR_T eventTypes;
eventTypes.push_back(eventType);
// Register it with this observer.
_notifiedMap[observer] = eventTypes;
// Register the observer for this type of event.
_notifiedVector[eventType].push_back(observer);
}
else
{
NOTIFIED_EVENT_TYPE_VECTOR_T& events = _mapIter->second;
bool found = false;
for(int idx = 0; idx < events.size() && !found; idx++)
{
if(events[idx] == eventType)
{
found = true;
break;
}
}
if(!found)
{
events.push_back(eventType);
_notifiedVector[eventType].push_back(observer);
}
}
}
void Notifier::RemoveEvent(NOTIFIED_EVENT_TYPE_VECTOR_T& eventTypes, NOTIFIED_EVENT_TYPE_T eventType)
{
int foundAt = -1;
for(int idx = 0; idx < eventTypes.size(); idx++)
{
if(eventTypes[idx] == eventType)
{
foundAt = idx;
break;
}
}
if(foundAt >= 0)
{
eventTypes.erase(eventTypes.begin()+foundAt);
}
}
void Notifier::RemoveNotified(NOTIFIED_VECTOR_T& notified, Notified* observer)
{
int foundAt = -1;
for(int idx = 0; idx < notified.size(); idx++)
{
if(notified[idx] == observer)
{
foundAt = idx;
break;
}
}
if(foundAt >= 0)
{
notified.erase(notified.begin()+foundAt);
}
}
void Notifier::Detach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType)
{
if(observer == NULL)
{
throw std::out_of_range("observer == NULL");
}
if(eventType < NE_MIN || eventType >= NE_MAX)
{
throw std::out_of_range("eventType out of range");
}
_mapIter = _notifiedMap.find(observer);
if(_mapIter != _notifiedMap.end())
{ // Was registered
// Remove it from the map.
RemoveEvent(_mapIter->second, eventType);
// Remove it from the vector
RemoveNotified(_notifiedVector[eventType], observer);
// If there are no events left, remove this observer completely.
if(_mapIter->second.size() == 0)
{
_notifiedMap.erase(_mapIter);
// If this observer was being removed during a chain of operations,
// cache them temporarily so we know the pointer is "dead".
_detached.push_back(observer);
}
}
}
void Notifier::Detach(Notified* observer)
{
if(observer == NULL)
{
throw std::out_of_range("observer == NULL");
}
_mapIter = _notifiedMap.find(observer);
if(_mapIter != _notifiedMap.end())
{
// These are all the event types this observer was registered for.
NOTIFIED_EVENT_TYPE_VECTOR_T& eventTypes = _mapIter->second;
for(int idx = 0; idx < eventTypes.size();idx++)
{
NOTIFIED_EVENT_TYPE_T eventType = eventTypes[idx];
// Remove this observer from the Notified list for this event type.
RemoveNotified(_notifiedVector[eventType], observer);
}
_notifiedMap.erase(_mapIter);
}
// If this observer was being removed during a chain of operations,
// cache them temporarily so we know the pointer is "dead".
_detached.push_back(observer);
}
Notified::~Notified()
{
Notifier::Instance().Detach(this);
}
// Return all events that this object is registered for.
vector<NOTIFIED_EVENT_TYPE_T> Notifier::GetEvents(Notified* observer)
{
vector<NOTIFIED_EVENT_TYPE_T> result;
_mapIter = _notifiedMap.find(observer);
if(_mapIter != _notifiedMap.end())
{
// These are all the event types this observer was registered for.
result = _mapIter->second;
}
return result;
}
// Return all objects registered for this event.
vector<Notified*> Notifier::GetNotified(NOTIFIED_EVENT_TYPE_T event)
{
return _notifiedVector[event];
}
NOTES:
You must call init() on the class before using it.
You don't have to use it as a singleton, or use the singleton template I used here. That is just to get a reference/init/shutdown mechanism in place.
This is from a larger code base. You can find some other examples on github here.

There was a topic on SO, where virtually all mechanisms available in C++ was enumerated, but can't find it.
It had a list something like this:
function pointers
functors: member function pointers wrapped along with this to object with overloaded operator()
Fast Delegates
Impossibly Fast Delegates
boost::signals
Qt signal-slots
Fast delegates and boost::function performance comparison article: link
Oh, by the way, premature optimization..., profile first then optimize, 80/20-rule, blah-blah, blah-blah, you know ;)
Happy coding!

Unless you can parameterize your handlers statically and get the inlined, std::function<...> is your best option. When type exact type needs to be erased or you need to call run-time specified function you'll have an indirection and, hence, an actual function call without the ability to get things inlined. std::function<...> does exactly this and you won't get better.

Related

Creating a C++ Event System

I've decided to begin making a game engine lately. I know most people don't finish theirs, and if I'm being honest I may not either. I'm doing this because I'm sick of googling "Cool C++ projects" and doing the 3 answers every single user gives (that'd be an address book or something similar, tic tac toe, and a report card generator or something like that). I like programming, but unfortunately I have no real use for it. Everything I would use it for I can do faster and easier in another way, or a solution already exists. However, in an effort to learn more than the basic level of C++ and do something that would teach me something that's truly in depth, I've revoked this policy and decided to begin a game engine, as it's something I've always been interested in. I've decided to model it loosely after Amazon's Lumberyard engine, as it's almost entirely C++ and gives me a good basis to learn from, as I can always just go there and do something with it to see how it behaves.
Onto the actual problem now:
I've got a working Entity Component system (yay), that although is in its early stages and not super great functionality wise, I'm very proud of. Honestly I never thought I'd get this far. I'm currently working with the Event Bus system. Now, I really love LY's EBus system. It's extremely easy to use and very straight forward, but from a programming newbie-ish's eyes it's black magic and witchcraft. I have no clue how they did certain things, so hopefully you do!
Making an EBus goes something like this:
#include <EBusThingy.h>
class NewEbusDealio
: public EbusThingy
{
public:
//Normally there's some setup work involved here, but I'm excluding it as I don't really feel that it's necessary for now. I can always add it later (see the footnote for details on what these actually are).
//As if by magic, this is all it takes to do it (I'd like to clarify that I'm aware that this is a pure virtual function, I just don't get how they generate so much usage out of this one line):
virtual void OnStuffHappening(arguments can go here if you so choose) = 0;
};
And that's it...
As if by magic, when you go to use it, all you have to do is this:
#include "NewEbusDealio.h"
class ComponentThatUsesTheBus
: public NewEbusDealio::Handler
{
public:
void Activate() override
{
NewEbusDealio::Handler::BusConnect();
}
protected:
void OnStuffHappening(arguments so chosen)
{
//Do whatever you want to happen when the event fires
}
};
class ComponentThatSendsEvents
{
public:
void UpdateOrWhatever()
{
NewEbusDealio::Broadcast(NewEbusDealio::Events::OnStuffHappening, arguments go here)
}
};
I just don't get how you can do this much stuff just by adding a single virtual function to NewEbusDealio. Any help on this is much appreciated. Sorry for so many text walls but I'd really like to get something out of this, and I've hit a massive brick wall on this bit. This may be way overkill for what I'm making, and it also may wind up being so much work that it's just not within the realm of possibility for one person to make in a reasonable amount of time, but if a simple version of this is possible I'd like to give it a go.
I'm putting this down here so people know what the setup work is. All you do is define a static const EBusHandlerPolicy and EBusAddressPolicy, which defines how many handlers can connect to each address on the bus, and whether the bus works on a single address (no address needed in event call), or whether you can use addresses to send events to handlers listening on a certain address. For now, I'd like to have a simple bus where if you send an event, all handlers receive it.
Not familiar with EBus you given, but event buses should be similar: one side creates an event and puts it into a list, the other side picks up events one by one and reacts.
As modern C++ gives us closure feature, it ismuch easier to implement a event bus now.
Following, I'm going to give a simple example, where looper is a event bus.
Be aware mutexs and conditional variables are necessary for this looper in production.
#include <queue>
#include <list>
#include <thread>
#include <functional>
class ThreadWrapper {
public:
ThreadWrapper() = default;
~ThreadWrapper() { Detach(); }
inline void Attach(std::thread &&th) noexcept {
Detach();
routine = std::forward<std::thread &&>(th);
}
inline void Detach() noexcept {
if (routine.joinable()) {
routine.join();
}
}
private:
std::thread routine{};
};
class Looper {
public:
// return ture to quit the loop, false to continue
typedef std::function<void()> Task;
typedef std::list<Task> MsgQueue;
Looper() = default;
~Looper() {
Deactivate();
}
// Post a method
void Post(const Task &tsk) noexcept {
Post(tsk, false);
}
// Post a method
void Post(const Task &tsk, bool flush) noexcept {
if(!running) {
return;
}
if (flush) msg_queue.clear();
msg_queue.push_back(tsk);
}
// Start looping
void Activate() noexcept {
if (running) {
return;
}
msg_queue.clear();
looping = true;
worker.Attach(std::thread{&Looper::Entry, this});
running = true;
}
// stop looping
void Deactivate() noexcept {
{
if(!running) {
return;
}
looping = false;
Post([] { ; }, true);
worker.Detach();
running = false;
}
}
bool IsActive() const noexcept { return running; }
private:
void Entry() noexcept {
Task tsk;
while (looping) {
//if(msg_queue.empty()) continue;
tsk = msg_queue.front();
msg_queue.pop_front();
tsk();
}
}
MsgQueue msg_queue{};
ThreadWrapper worker{};
volatile bool running{false};
volatile bool looping{false};
};
An example to use this Looper:
class MySpeaker: public Looper{
public:
// Call SayHi without blocking current thread
void SayHiAsync(const std::string &msg){
Post([this, msg] {
SayHi(msg);
});
}
private:
// SayHi will be called in the working thread
void SayHi() {
std::cout << msg << std::endl;
}
};

Alternative to a function pointer with reference capture

I'm writing an event handler that listens for key presses, then calls a handler on any pressed keys. My goal was to allow something like this:
Entity player(0, 0);
EventHandler eh([&](char c) {
switch (c) {
case 'W': {
player.moveBy(0,-1);
break;
}
case 'S': {
player.moveBy(0, 1);
break;
}
case 'A': {
player.moveBy(-1, 0);
break;
}
case 'D': {
player.moveBy(1, 0);
break;
}
}
});
where an Entity is just a movable point-like object.
I was all set, then I realized that lambdas with referential captures can't be made into a function pointer (the reason makes sense, in retrospect).
The only alternative I could find was to use std::/boost::function, but the syntax is rather ugly, and apparently they come with a decent amount of overhead.
What's a good alternative to this system? I want to be able to pass in some kind of "handler" to EventHandler that accepts a character, and is capable of carrying out side effects on some external scope.
In the below source, LockedQueue is a FIFO queue that's been made thread safe using mutexes.
EventHandler.h:
#ifndef EVENT_HANDLER_H
#define EVENT_HANDLER_H
#include <vector>
#include <atomic>
#include "LockedQueue.h"
class EventHandler {
typedef void(*KeyHandler)(char);
std::atomic<bool> listenOnKeys = false;
std::vector<char> keysToCheck;
LockedQueue<char> pressedKeys;
KeyHandler keyHandler = nullptr;
void updatePressedKeys();
void actOnPressedKeys();
public:
EventHandler();
EventHandler(KeyHandler);
~EventHandler();
void setKeyHandler(KeyHandler);
void setKeysToListenOn(std::vector<char>);
void listenForPresses(int loopMSDelay = 100);
void stopListening();
};
#endif
EventHandler.cpp:
#include "EventHandler.h"
#include <windows.h>
#include <WinUser.h>
#include <thread>
#include <stdexcept>
EventHandler::EventHandler() {
}
EventHandler::EventHandler(KeyHandler handler) {
keyHandler = handler;
}
EventHandler::~EventHandler() {
stopListening();
}
void EventHandler::updatePressedKeys() {
for (char key : keysToCheck) {
if (GetAsyncKeyState(key)) {
pressedKeys.push(key);
}
}
}
void EventHandler::actOnPressedKeys() {
while (!pressedKeys.empty()) {
//Blocking if the queue is empty
//We're making sure ahead of time though that it's not
keyHandler(pressedKeys.waitThenPop());
}
}
void EventHandler::setKeyHandler(KeyHandler handler) {
keyHandler = handler;
}
void EventHandler::setKeysToListenOn(std::vector<char> newListenKeys) {
if (listenOnKeys) {
throw std::runtime_error::runtime_error(
"Cannot change the listened-on keys while listening"
);
//This could be changed to killing the thread by setting
// listenOnKeys to false, changing the keys, then restarting
// the listening thread. I can't see that being necessary though.
}
//To-Do:
//Make sure all the keys are in upper-case so they're
// compatible with GetAsyncKeyState
keysToCheck = newListenKeys;
}
void EventHandler::listenForPresses(int loopMSDelay) {
listenOnKeys = true;
std::thread t([&]{
do {
updatePressedKeys();
actOnPressedKeys();
std::this_thread::sleep_for(std::chrono::milliseconds(loopMSDelay));
} while (listenOnKeys);
});
t.join();
}
void EventHandler::stopListening() {
listenOnKeys = false;
}
EDIT:
Whoops. Note that listenForPresses is "broken" because I'm joining inside the function, so control never leaves it. I'm going to need to figure out a workaround. Doesn't change the question though, but the code isn't testable in it's current state.
The only alternative I could find was to use std::/boost::function, but the syntax is rather ugly, and apparently they come with a decent amount of overhead.
The overhead is decent compared to an inlinable function, but it's measured in nanoseconds. If you're only calling the function 60 times a second, the overhead is immeasurable.
That said, if you need to be able to change the event handler at any time, your only alternative is virtual method calls, with similar overhead. The performance impact of these choices are explored thoroughly in this article: Member Function Pointers and the Fastest Possible C++ Delegates.
If you are happy to restrict the EventHandler object to executing a single block of code defined at compile-time, use templates to store an instance of the compiler's generated type for the lambda; this should allow the compiler to perform more optimisations, as it can know for sure what code is being called. In this case, KeyHandler becomes a template type, and the type of a lambda can either be found with the decltype keyword:
template <class KeyHandler>
class EventHandler {
// elided
}
void EventLoopDecltype() {
Entity player(0, 0);
auto myEventHandler = [&](char ch) { /* elided */ };
EventHandler<decltype(myEventHandler)> eh(myEventHandler);
}
or (more conveniently, for the caller) inferred as an argument to a template function:
template <class KeyHandler>
EventHandler<KeyHandler> MakeEventHandler(KeyHandler handler) {
return EventHandler<KeyHandler>(handler);
}
void EventLoopInferred() {
Entity player(0, 0);
auto eh = MakeEventHandler([&](char c) {
// elided
});
}
std::function and boost::function do not come with any overhead that's remotely meaningful considering how light your usage of them would be in this case. You've made a critical error by discarding the solution before determining that the purported downsides actually apply to you.
You could of course also use a template as described in the other answer, but there's really no need to.

How should I restructure this event-handling code?

I've been reading some C++ books (Sutters, Meyers) lately which motivated me to start using smart pointers (and object destruction in general) more effectively. But now I'm not sure how to fix what I have.
Specifically, I now have a IntroScene class which inherits from both Scene and InputListener.
Scene isn't really relevant, but the InputListener subscribes to an InputManager on construction,
and unsubs again on destruction.
class IntroScene : public sfg::Scene, public sfg::InputListener {
/*structors, inherited methods*/
virtual bool OnEvent(sf::Event&) override; //inputlistener
}
But now, if the inputmanager sends events over to a scene, and the scene decided to replace itself
because of it, I have function running on an object that no longer exists.
bool IntroScene::OnEvent(sf::Event& a_Event) {
if (a_Event.type == sf::Event::MouseButtonPressed) {
sfg::Game::Get()->SceneMgr()->Replace(ScenePtr(new IntroScene()));
} //here the returned smartpointer kills the scene/listener
}
Side-question: Does that matter? I googled it but did not find a definite yes or no. I do know 100%
no methods are invoked on the destroyed object after it is destroyed.
I can store the Replace() return value until the end of the OnEvent() method if I have to.
The real problem is InputListener
InputListener::InputListener() {
Game::Get()->InputMgr()->Subscribe(this);
}
InputListener::~InputListener() {
if (m_Manager) m_Manager->Unsubscribe(this);
}
since it is called during OnEvent(), which is called by InputManager during HandleEvents()
void InputManager::HandleEvents(EventQueue& a_Events) const {
while (!a_Events.empty()) {
sf::Event& e = a_Events.front();
for (auto& listener : m_Listeners) {
if (listener->OnEvent(e)) //swallow event
break;
}
a_Events.pop();
}
void InputManager::Subscribe(InputListener* a_Listener) {
m_Listeners.insert(a_Listener);
a_Listener->m_Manager = this;
}
void InputManager::Unsubscribe(InputListener* a_Listener) {
m_Listeners.erase(a_Listener);
a_Listener->m_Manager = nullptr;
}
So when the new Scene+Listener is created, and when the old one is destroyed, the list m_Listeners is modified during the loop. So the thing breaks.
I've thought about setting a flag when starting and stopping the loop, and storing (un)subscriptions that happen while it is set in a separate list, and handle that after. But it feels a bit hacky.
So, how can I actually redesign this properly to prevent these kind of situations? Thanks in advance.
EDIT, Solution:
I ended up going with the loop flags and deferred entry list (inetknight's answer below)
for subscription only, since that can be safely done later.
Unsubscriptions have to be dealt with immediately, so instead of storing raw pointers I store a (pointer-mutable bool) pair (mutable since a set only returns a const_iterator). I set the bool to false when that happens and check for it in the event loop (see dave's comment below).
Not sure it's cleanest possible solution, but it works like a charm. Thanks a lot guys
Side-question: Does that matter? I googled it but did not find a definite yes or no. I do know 100% no methods are invoked on the destroyed object after it is destroyed. I can store the Replace() return value until the end of the OnEvent() method if I have to.
If you know 100% no methods are invoked ont he destroyed object and none of its member variables are accessed, then it's safe. Whether or not it's intended is up to you.
You could have another list of objects which have requested to be un/subscribed. Then after you've told everyone in the list of events, you would then process the list of un/subscription requests before continuing on to the next event.
/* this should be a member of InputManager however you did not provide a class definition */
typedef std::pair<InputListener *, bool> SubscriptionRequest;
bool handleEventsActive = false;
std::vector<SubscriptionRequest> deferredSubscriptionRequests;
void InputManager::HandleEvents(EventQueue& a_Events) const {
// process events
handleEventsActive = true;
while (!a_Events.empty()) {
sf::Event& e = a_Events.front();
for (auto& listener : m_Listeners)
{
//swallow event
if (listener->OnEvent(e)) {
break;
}
}
a_Events.pop();
// process deferred subscription requests occurred during event
while ( not deferredSubscriptionRequests.empty() ) {
SubscriptionRequest request = deferredSubscriptionRequests.back();
deferredSubscriptionRequests.pop_back();
DoSubscriptionRequest(request);
}
}
handleEventsActive = false;
}
void InputManager::DoSubscriptionRequest(SubscriptionRequest &request) {
if ( request.second ) {
m_Listeners.insert(request.first);
request.first->m_Manager = this;
} else {
m_Listeners.erase(request.first);
request.first->m_Manager = nullptr;
}
}
void InputManager::Subscribe(InputListener* a_Listener)
{
SubscriptionRequest request{a_Listener, true};
if ( handleEventsActive ) {
deferredSubscriptionRequests.push_back(request);
} else {
DoSubscriptionRequest(request);
}
}
void InputManager::Unsubscribe(InputListener* a_Listener)
{
SubscriptionRequest request{a_Listener, false};
if ( handleEventsActive ) {
deferredSubscriptionRequests.push_back(request);
} else {
DoSubscriptionRequest(request);
}
}

How can I do automata/state machine coding in C++?

I have used it in another programming language and It's very usefull.
I cannot find anything about this for C++.
Let's for example take the following code:
void change();
enum
{
end = 0,
gmx
}
int
gExitType;
int main()
{
gExitType = end;
SetTimer(&change, 10000, 0);
return 0;
}
void ApplicationExit()
{
switch (gExitType)
{
case end:
printf("This application was ended by the server");
case gmx:
printf("This application was ended by the timer");
}
::exit(0);
}
void change()
{
gExitType = gmx;
ApplicationExit();
}
That's kind of how we would do it in C++, but when using state machine/automata I could do something like this in the other language:
void change();
int main()
{
state exitType:end;
SetTimer(&change, 10000, 0);
return 0;
}
void ApplicationExit() <exitType:end>
{
printf("This application was ended by the server");
}
void ApplicationExit() <exitType:gmx>
{
printf("This application ended by the timer");
}
void change()
{
state exitType:gmx;
ApplicationExit();
}
In my opition this is a really elegant way to achieve things.
How would I do this in C++? This code doesn't seem to work (obviously as I cannot find anything automata related to C++)
To clarify my opinion:
So what are the advantages to using this technique? Well, as you can clearly see the code is smaller; granted I added an enum to the first version to make the examples more similar but the ApplicationExit functions are definately smaller. It's also alot more explicit - you don't need large switch statements in functions to determine what's going on, if you wanted you could put the different ApplicationExits in different files to handle different sets of code independently. It also uses less global variables.
There are C++ libraries like Boost.statechart that specifically try to provide rich support for encoding state machines:
http://www.boost.org/doc/libs/1_54_0/libs/statechart/doc/tutorial.html
Besides this, one very elegant way to encode certain types of state machines is by defining them as a couroutine:
http://c2.com/cgi/wiki?CoRoutine
http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines/
Coroutines are not directly supported in C++, but there are two possible approaches for
implementing them:
1) Using a technique similar to implementing a duff's device, explained in details here:
http://blog.think-async.com/search/label/coroutines
This is very similar to how C#'s iterators work for example and one limitation is that yielding form the coroutine can be done only from the topmost function in the coroutine call-stack. OTOH, the advantage of this method is that very little memory is required for each instance of the coroutine.
2) Allocating a separate stack and registers space for each coroutine.
This essentially makes the coroutine a full-blown thread of execution with the only difference that the user has full responsibility for the thread scheduling (also known as cooperative multi-tasking).
A portable implementation is available from boost:
http://www.boost.org/doc/libs/1_54_0/libs/coroutine/doc/html/coroutine/intro.html
For this particular example, you could use objects and polymorphism to represent the different states. For example:
class StateObject
{
public:
virtual void action(void) = 0;
};
class EndedBy : public StateObject
{
private:
const char *const reason;
public:
EndedBy( const char *const reason_ ) : reason( reason_ ) { }
virtual void action(void)
{
puts(reason);
}
};
EndedBy EndedByServer("This application was ended by the server");
EndedBy EndedByTimer ("This application ended by the timer");
StateObject *state = &EndedByServer;
void change()
{
state = &EndedByTimer;
}
void ApplicationExit()
{
state->action();
::exit(0);
}
int main()
{
SetTimer(&change, 10000, 0);
// whatever stuff here...
// presumably eventually causes ApplicationExit() to get called before return 0;
return 0;
}
That said, this isn't great design, and it isn't an FSM in the general sense. But, it would implement your immediate need.
You might look up the State Pattern (one reference: http://en.wikipedia.org/wiki/State_pattern ) for a more general treatment of this pattern.
The basic idea, though, is that each state is a subclass of some common "state" class, and you can use polymorphism to determine the different actions and behaviors represented by each state. A pointer to the common "state" base class then keeps track of the state you're currently in.
The state objects may be different types, or as in my example above, different instances of the same object configured differently, or a blend.
You can use Template value specialization over an int to achieve pretty much what you want.
(Sorry I'm at my tablet so I cannot provide an example, I will update on Sunday)

C++ Critical Section not working

My critical section code does not work!!!
Backgrounder.run IS able to modify MESSAGE_QUEUE g_msgQueue and LockSections destructor hadn't been called yet !!!
Extra code :
typedef std::vector<int> MESSAGE_LIST; // SHARED OBJECT .. MUST LOCK!
class MESSAGE_QUEUE : MESSAGE_LIST{
public:
MESSAGE_LIST * m_pList;
MESSAGE_QUEUE(MESSAGE_LIST* pList){ m_pList = pList; }
~MESSAGE_QUEUE(){ }
/* This class will be shared between threads that means any
* attempt to access it MUST be inside a critical section.
*/
void Add( int messageCode ){ if(m_pList) m_pList->push_back(messageCode); }
int getLast()
{
if(m_pList){
if(m_pList->size() == 1){
Add(0x0);
}
m_pList->pop_back();
return m_pList->back();
}
}
void removeLast()
{
if(m_pList){
m_pList->erase(m_pList->end()-1,m_pList->end());
}
}
};
class Backgrounder{
public:
MESSAGE_QUEUE* m_pMsgQueue;
static void __cdecl Run( void* args){
MESSAGE_QUEUE* s_pMsgQueue = (MESSAGE_QUEUE*)args;
if(s_pMsgQueue->getLast() == 0x45)printf("It's a success!");
else printf("It's a trap!");
}
Backgrounder(MESSAGE_QUEUE* pMsgQueue)
{
m_pMsgQueue = pMsgQueue;
_beginthread(Run,0,(void*)m_pMsgQueue);
}
~Backgrounder(){ }
};
int main(){
MESSAGE_LIST g_List;
CriticalSection crt;
ErrorHandler err;
LockSection lc(&crt,&err); // Does not work , see question #2
MESSAGE_QUEUE g_msgQueue(&g_List);
g_msgQueue.Add(0x45);
printf("%d",g_msgQueue.getLast());
Backgrounder back_thread(&g_msgQueue);
while(!kbhit());
return 0;
}
#ifndef CRITICALSECTION_H
#define CRITICALSECTION_H
#include <windows.h>
#include "ErrorHandler.h"
class CriticalSection{
long m_nLockCount;
long m_nThreadId;
typedef CRITICAL_SECTION cs;
cs m_tCS;
public:
CriticalSection(){
::InitializeCriticalSection(&m_tCS);
m_nLockCount = 0;
m_nThreadId = 0;
}
~CriticalSection(){ ::DeleteCriticalSection(&m_tCS); }
void Enter(){ ::EnterCriticalSection(&m_tCS); }
void Leave(){ ::LeaveCriticalSection(&m_tCS); }
void Try();
};
class LockSection{
CriticalSection* m_pCS;
ErrorHandler * m_pErrorHandler;
bool m_bIsClosed;
public:
LockSection(CriticalSection* pCS,ErrorHandler* pErrorHandler){
m_bIsClosed = false;
m_pCS = pCS;
m_pErrorHandler = pErrorHandler;
// 0x1AE is code prefix for critical section header
if(!m_pCS)m_pErrorHandler->Add(0x1AE1);
if(m_pCS)m_pCS->Enter();
}
~LockSection(){
if(!m_pCS)m_pErrorHandler->Add(0x1AE2);
if(m_pCS && m_bIsClosed == false)m_pCS->Leave();
}
void ForceCSectionClose(){
if(!m_pCS)m_pErrorHandler->Add(0x1AE3);
if(m_pCS){m_pCS->Leave();m_bIsClosed = true;}
}
};
/*
Safe class basic structure;
class SafeObj
{
CriticalSection m_cs;
public:
void SafeMethod()
{
LockSection myLock(&m_cs);
//add code to implement the method ...
}
};
*/
#endif
Two questions in one. I don't know about the first, but the critical section part is easy to explain. The background thread isn't trying to claim the lock and so, of course, is not blocked. You need to make the critical section object crt visible to the thread so that it can lock it.
The way to use this lock class is that each section of code that you want serialised must create a LockSection object and hold on to it until the end of the serialised block:
Thread 1:
{
LockSection lc(&crt,&err);
//operate on shared object from thread 1
}
Thread 2:
{
LockSection lc(&crt,&err);
//operate on shared object from thread 2
}
Note that it has to be the same critical section instance crt that is used in each block of code that is to be serialised.
This code has a number of problems.
First of all, deriving from the standard containers is almost always a poor idea. In this case you're using private inheritance, which reduces the problems, but doesn't eliminate them entirely. In any case, you don't seem to put the inheritance to much (any?) use anyway. Even though you've derived your MESSAGE_QUEUE from MESSAGE_LIST (which is actually std::vector<int>), you embed a pointer to an instance of a MESSAGE_LIST into MESSAGE_QUEUE anyway.
Second, if you're going to use a queue to communicate between threads (which I think is generally a good idea) you should make the locking inherent in the queue operations rather than requiring each thread to manage the locking correctly on its own.
Third, a vector isn't a particularly suitable data structure for representing a queue anyway, unless you're going to make it fixed size, and use it roughly like a ring buffer. That's not a bad idea either, but it's quite a bit different from what you've done. If you're going to make the size dynamic, you'd probably be better off starting with a deque instead.
Fourth, the magic numbers in your error handling (0x1AE1, 0x1AE2, etc.) is quite opaque. At the very least, you need to give these meaningful names. The one comment you have does not make the use anywhere close to clear.
Finally, if you're going to go to all the trouble of writing code for a thread-safe queue, you might as well make it generic so it can hold essentially any kind of data you want, instead of dedicating it to one specific type.
Ultimately, your code doesn't seem to save the client much work or trouble over using the Windows functions directly. For the most part, you've just provided the same capabilities under slightly different names.
IMO, a thread-safe queue should handle almost all the work internally, so that client code can use it about like it would any other queue.
// Warning: untested code.
// Assumes: `T::T(T const &) throw()`
//
template <class T>
class queue {
std::deque<T> data;
CRITICAL_SECTION cs;
HANDLE semaphore;
public:
queue() {
InitializeCriticalSection(&cs);
semaphore = CreateSemaphore(NULL, 0, 2048, NULL);
}
~queue() {
DeleteCriticalSection(&cs);
CloseHandle(semaphore);
}
void push(T const &item) {
EnterCriticalSection(&cs);
data.push_back(item);
LeaveCriticalSection(&cs);
ReleaseSemaphore(semaphore, 1, NULL);
}
T pop() {
WaitForSingleObject(semaphore, INFINITE);
EnterCriticalSection(&cs);
T item = data.front();
data.pop_front();
LeaveCriticalSection(&cs);
return item;
}
};
HANDLE done;
typedef queue<int> msgQ;
enum commands { quit, print };
void backgrounder(void *qq) {
// I haven't quite puzzled out what your background thread
// was supposed to do, so I've kept it really simple, executing only
// the two commands listed above.
msgQ *q = (msgQ *)qq;
int command;
while (quit != (command = q->pop()))
printf("Print\n");
SetEvent(done);
}
int main() {
msgQ q;
done = CreateEvent(NULL, false, false, NULL);
_beginthread(backgrounder, 0, (void*)&q);
for (int i=0; i<20; i++)
q.push(print);
q.push(quit);
WaitForSingleObject(done, INFINITE);
return 0;
}
Your background thread needs access to the same CriticalSection object and it needs to create LockSection objects to lock it -- the locking is collaborative.
You are trying to return the last element after popping it.