Click here to Skip to main content
15,883,705 members
Articles / Programming Languages / C++
Tip/Trick

Wrapping a C++ Callback in a .NET System::Action

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
17 Nov 2011CPOL 20.3K   4   1
Wrapping a C++ callback in a .NET Action so you can use the .NET Task Parallel Library
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.

C++
// This class bridges a C++ callback to a .NET Action, which
// can be queued up in a .NET Task.
template<typename T1, typename T2>
ref class CallbackToAction
{
public:
  typedef void (CallbackHandler)(T1, T2);

  // Converts function pointer and parameters to an action. Note that
  // the arguments need to be either pointers, values types, or managed pointers.
  // You cannot pass objects by value.
  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:

C++
#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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder Cheesy Design
Taiwan Taiwan
John graduated from the University of South Australia in 1997 with a Bachelor of Electronic Engineering Degree, and since then he has worked on hardware and software in many fields including Aerospace, Defence, and Medical giving him over 10 of years experience in C++ and C# programming. In 2009 John Started his own contracting company doing business between Taiwan and Australia.

Comments and Discussions

 
Praisethanks Pin
Lucky Vdb2-May-21 2:39
professionalLucky Vdb2-May-21 2:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.