2011-07-12 37 views
2

我想讓Windows線程池(QueueUserWorkItem())調用我的類的成員函數。如何讓Windows線程池調用類成員函數?

不幸的是,這不能通過將成員函數指針作爲參數傳遞給QueueUserWorkItem()來直接完成。

難以做到的是多於一個成員函數必須是可調用的,並且它們具有不同的簽名(儘管這些成員函數都返回void)。

一個可能需要添加幾層抽象才能使這個工作,但我不知道如何處理這個。有任何想法嗎?

回答

1

這可能有幫助。 可以使用TR1 ::()函數和tr1 ::綁定到「合併」各種電話:

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

函數對象可以作爲一個可調用對象傳遞的地址(僅需要一個地址)。

+0

太棒了!正是我需要的。驚人的STL魔術。感謝您向我介紹這一點。現在唯一的問題是線程安全。當線程池嘗試使用它時,函數對象很可能會死亡。我想我需要堆構造函數,但對內存泄漏警惕。關於如何處理這個問題的任何想法? – links77

+0

是的,你需要在堆上構建它。消費線程可以刪除它,但我會建議使用tr1:shared_ptr() – John

0

實施例: 在你的類添加:

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對第二個例子 ,你也可以改變結構來保持傳遞參數