In this tip, you will see how to use a template class to wrap a C++ callback in an action.
Introduction
Here's a template class for wrapping a C++ callback in an action. This is so you can queue up tasks in C++ using the .NET Task Parallel Library.
template<typename T1, typename T2>
ref class CallbackToAction
{
public:
typedef void (CallbackHandler)(T1, T2);
static System::Action^ Convert(CallbackHandler* handler, T1 arg1, T2 arg2)
{
CallbackToAction<T1,T2>^ callbackToAction = gcnew CallbackToAction<T1,T2>();
callbackToAction->_handler = handler;
callbackToAction->_arg1 = arg1;
callbackToAction->_arg2 = arg2;
return callbackToAction->ToAction();
}
private:
void DoCallback()
{
_handler(_arg1, _arg2);
}
System::Action^ ToAction()
{
return gcnew Action(this, &CallbackToAction::DoCallback);
}
CallbackHandler* _handler;
T1 _arg1;
T2 _arg2;
};
Here's a whole console app that shows you how to use it:
#include "CallbackToAction.h"
using namespace System;
using namespace System::Threading;
using namespace System::Threading::Tasks;
class MyClass
{
int _sleepTime;
public:
MyClass(int sleepTime)
{
_sleepTime = sleepTime;
}
void DoSomething()
{
Thread::Sleep(_sleepTime);
}
};
typedef CallbackToAction<MyClass*, Barrier^> MyCallbackToAction;
void CallbackFunction(MyClass* myObject, Barrier^ barrier)
{
myObject->DoSomething();
Console::WriteLine(L"A task has finished");
barrier->RemoveParticipant();
}
int main(array<System::String ^> ^args)
{
Barrier^ barrier = gcnew Barrier(3);
Console::WriteLine(L"Queing 2 tasks");
MyClass myObject1(1000);
MyClass myObject2(3000);
Task::Factory->StartNew(MyCallbackToAction::Convert
(&CallbackFunction, &myObject1, barrier));
Task::Factory->StartNew(MyCallbackToAction::Convert
(&CallbackFunction, &myObject2, barrier));
Console::WriteLine(L"Waiting");
barrier->SignalAndWait();
Console::WriteLine(L"All Finished. Press Enter");
Console::ReadLine();
return 0;
}
History
- 17th November, 2011: Initial version