Как заставить пул потоков Windows вызывать функцию-член класса?

Я хочу, чтобы пул потоков Windows (QueueUserWorkItem ()) вызывал функции-члены моего класса.

К сожалению, это невозможно сделать напрямую, передав указатель на функцию-член в качестве аргумента функции QueueUserWorkItem ().

Сложность состоит в том, что несколько функций-членов должны быть вызываемыми и иметь разные подписи (хотя все они возвращают void).

Вероятно, нужно добавить несколько уровней абстракции, чтобы это работало, но я не уверен, как к этому подойти. Любые идеи?


person links77    schedule 12.07.2011    source источник


Ответы (2)


Это может помочь. Вы можете использовать tr1 :: function () и tr1 :: bind для «объединения» различных вызовов:

   #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;
   }

Адрес функционального объекта может быть передан как один вызываемый объект (требуется только один адрес).

person John    schedule 12.07.2011
comment
Потрясающий! Как раз то, что мне нужно. Удивительная магия STL. Спасибо, что познакомили меня с этим. Единственная проблема сейчас - безопасность потоков. Функциональный объект, скорее всего, будет мертв, когда пул потоков попытается его использовать. Я предполагаю, что мне нужно создать кучу функции, но опасаюсь утечек памяти. Есть идеи, как я могу с этим справиться? - person links77; 13.07.2011
comment
Да, нужно построить в куче. Потребляющий поток может удалить его, но я бы рекомендовал использовать tr1: shared_ptr (‹tr1 / memory›) - person John; 13.07.2011

Пример: в вашем классе добавьте:

char m_FuncToCall;

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

Сделайте участника для добавления в очередь, затем

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

или создать

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

    }ARGUMENT_TO_PASS;

а потом

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

Если вам нужны дополнительные объяснения, не стесняйтесь спрашивать :)

РЕДАКТИРОВАТЬ: Вам нужно будет изменить ThreadStartRoutine для второго примера, и вы также можете изменить структуру для хранения передаваемого аргумента

person Djole    schedule 12.07.2011