遇到的问题
我们在编程中需要把数据封装成一个类,调用pthread_create 利用成员函数去创建一个线程往往是不成功的!
error: argumentof type ‘void* (Threadpool::)(void*)’ does not match ‘void* (*)(void*)’
出现类型不匹配的问题。因为pthread_create需要的参数类型为void*(*)(void*),而thread_rounter作为类的成员函数时其类型是void* (Threadpool::)(void*)的成员函数指针。我们知道类的成员函数在经过编译器处理之后,会变成带有this指针参数的全局函数,所以类型注定是不会匹配的。
解决方案
天无绝人之路,尤其是对于C++这种被称为Wenger巨人刀(http://coolshell.cn/articles/6639.html#more-6639)的超级语言一定会有各种奇淫技巧提供出超乎想象的解决方案的。
各种编程语言的调侃图
声明static 成员函数作为线程函数
但是如果将thread_rounter声明为static类型,那么编译器会将static形式的函数,转换成不带this指针的全局函数,所以其类型可以与pthread_create需要的参数类型相匹配。但是类的静态成员函数无法访问类的非静态成员,不过这可以通过传递this指针解决这个问题。
staticvoid*threadfun(void*)
{
//dosomething
}
通过全局函数回调成员函数
void *thread (void *tmp)/线程执行函数
{
ClassName*p=( ClassName *)tmp;
//通过p指针间接访问类的非静态成员
}
终极解决方案C++模板
//声明定义一个模板函数
template <typename TYPE, void(TYPE::*_RunThread)() >
void* _thread_t(void* param)
{
TYPE* This = (TYPE*)param;
This->_RunThread();
return NULL;
}
/*
_thread_t:为模板函数名,可随意起
TYPE:类名
_ RunThread:为TYPE类中成员函数的名称,在这里必须是pbulic 。不可以任意取名。返回类型和参数必须和类中的一致。
*/
class MyClass
{
public:
MyClass();
void _RunThread();
private:
pthread_t tid;
};
void MyClass::_RunThread()
{
this->DoSomeThing();
//...
}
MyClass::MyClass()
{
//利用C++强大的模板功能巧妙滴实现了函数转换
pthread_create(&tid, NULL, _thread_t<MyClass,&MyClass::_RunThread>, this);
}
函数模版不单可以替换类型本身,还能替换类型的成员函数。
注意:1、名称只能是_RunThread,不能在指定模版参数的时候修改;
2、_RunThread只能是public的,除非把_thread_t定义到MyClass的内部。
总结
这些奇淫技巧没有必要记住,用的时候能想起来查的到即可。以上说做的工作就只有一个目的,把函数类型转换成 void*(*)(void*)类型的。同理可以把这种技巧移植到其他的需要的地方,比如可以把成员函数转换成 T(*)(T*)的函数,这里就不一一解释了。
如果读者看到这里没有明白以上所说的是什么意思或者有点晕,没有关系,照猫画虎用就可以了。建议读者从新阅读C++教