I'm working in a c++ framework, mostly written before c++11, that allows us to fire events from a thread to a different thread (assuming that the receiving thread is running an event queue, so it's mainly used to fire events to the main UI thread from a helper thread).
Currently, the code to accomplish this is very verbose - it requires us to define two classes:
- An event class that contains any information we want to transfer.
- A listener class that handles the event in the receiving thread.
We've recently moved to c++11/14 and have been working on updating a lot of our code to use smart pointers, standard containers, and lambdas. I'd like to write a generic class that allows me to send a lambda to be run in a different thread. Something like:
mBoundary = make_unique<ThreadBoundary>( []( int value ) { doSomething( value ); } );
mBoundary->callInMainThread( 47 );
ThreadBoundary boundary2( []( std::string value ) { displayString( value ); } );
boundary2.callInMainThreadWait( "Show this string to the user" );
As an initial attempt, I've currently got this working with a lambda that doesn't take any parameters, built on top of the current framework functionality (omitting error checking, cleanup, etc):
class ThreadBoundary
{
public:
ThreadBoundary( std::function<void()> function ):mFunction( function )
{
mListener = make_shared<ThreadBoundaryListener>();
cApplication::addThreadBoundaryListener( mListener );
}
void callInMainThread()
{
cApplication::fireEventInMainThread( new ThreadBoundaryEvent( mFunction ) );
}
class ThreadBoundaryEvent:public FrameworkThreadBoundaryEvent
{
public:
ThreadBoundaryEvent( std::function<void()> function )
{
mFunction = function;
}
void call() { mFunction(); }
private:
std::function<void()> mFunction;
};
class ThreadBoundaryListener:public FrameworkThreadBoundaryListener
{
public:
ThreadBoundaryListener() {}
void handleEvent( const FrameworkThreadBoundaryEvent* event )
{
dynamic_cast<const ThreadBoundaryEvent*>( event )->call();
}
};
private:
shared_ptr<ThreadBoundaryListener> mListener;
std::function<void()> mFunction;
};
This allows me to fire "one-off" events to the main thread, however, without being able to send along parameters it's functionality is pretty limited.
I'd like to make this class use variadic templates so that I can pass anything to the callInMainThread function. However, I haven't been able to figure out how to store the parameter pack in the event and pass it along to the function inside call(). So my questions are:
- Is it possible to store a parameter pack and later pass it to a std::function.
- Is there a better way to do this in c++11/14 that doesn't require a huge redesign? Our framework is currently wrapping OS functionality to accomplish this (i.e. on Windows it uses SendMessage vs performSelectorOnMainThread in OS X).
Aucun commentaire:
Enregistrer un commentaire