2

I want the Windows thread pool (QueueUserWorkItem()) to call my class' member functions.

Unfortunately this cannot be done directly by passing a member function pointer as an argument to QueueUserWorkItem().

What makes it difficult is that more than one member function must be callable and they have different signatures (all return void though).

One probably need to add a few layers of abstraction to get this to work, but I'm not sure how to approach this. Any ideas?

links77
  • 1,534
  • 4
  • 14
  • 20

2 Answers2

1

This might help. You can use tr1::function () and tr1::bind to "coalesce" various calls:

   #include <iostream>
   #include <tr1/functional>
   using namespace std;
   using namespace tr1;

   class A
   {
   public:
      void function(int i) { cout << "Called A::function with i=" << i << endl; }
   };

   void different_function(double c) {
       cout << "Called different_function with c=" << c << endl;
   }


   int main(int argc, char* argv[])
   {
      function<void()> f = bind(different_function, 3.14165);
      f();

      A a;
      f = bind(&A::function, a, 10);
      f();

      return 0;
   }

The address of the function object can be passed as a single callable object (needing only one address).

John
  • 2,326
  • 1
  • 19
  • 25
  • Awesome! Just what I need. Amazing STL magic. Thank you for introducing me to this. The only problem now is thread safety. The function object will most likely be dead when the thread pool tries to use it. I guess I need to heap construct the function, but wary of memory leaks. Any ideas on how I can handle this? – links77 Jul 13 '11 at 07:25
  • Yes, you need to construct it on the heap. The consuming thread can delete it, but I would recommend using tr1:shared_ptr () – John Jul 13 '11 at 13:16
0

Example: In your class add:

char m_FuncToCall;

    static DWORD __stdcall myclass::ThreadStartRoutine(LPVOID myclassref)
    {
      myclass* _val =  (myclass*)myclassref;
      switch(m_FuncToCall)
      {
         case 0:
          _val->StartMyOperation();
         break;
       }
       return 0;
    }

Make a member for adding to queue then

void myclass::AddToQueue(char funcId)
 {
    m_FuncToCall=funcId;
   QueueUserWorkItem(ThreadStartRoutine,this,WT_EXECUTEDEFAULT);
 }

or create

typedef void (*MY_FUNC)(void);
    typedef struct _ARGUMENT_TO_PASS
    {
     myclass* classref;
     MY_FUNC func;

    }ARGUMENT_TO_PASS;

and then

void myclass::AddToQueue(MY_FUNC func)
{
   ARGUMENT_TO_PASS _arg;
   _arg.func = func;
   _arg.classref = this;
    QueueUserWorkItem(ThreadStartRoutine,&_arg,WT_EXECUTEDEFAULT);
}

If you need further explanation feel free to ask :)

EDIT: You'll need to change the ThreadStartRoutine for the second example and you can also change the struct to hold the passing argument

Djole
  • 1,145
  • 5
  • 10