2011-07-12 38 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对第二个例子 ,你也可以改变结构来保持传递参数