近日需要将线程池封装成c 类,类名为threadpool。在类的成员函数exec_task中调用pthread_create去启动线程执行例程thread_rounter。编译之后报错如下:
spfs_threadpool.cpp: in member function ‘int threadpool::exec_task(task*)’:
spfs_threadpool.cpp:174: error: argument of type ‘void* (threadpool::)(void*)’ does not match ‘void* (*)(void*)’
出现类型不匹配的问题。因为pthread_create需要的参数类型为void* (*)(void*),而thread_rounter作为类的成 员函数时其类型是void* (threadpool::)(void*)的成员函数指针。我们知道类的成员函数在经过编译器处理之后,会变成带有 this指针参数的全局函数,所以类型注定是不会匹配的。但是如果将thread_rounter声明为static类型,那么编译器会将static形 式的函数,转换成不带this指针的全局函数,所以其类型可以与pthread_create需要的参数类型相匹配。但是类的静态成员函数无法访问类的非 静态成员,不过这可以通过传递this指针解决这个问题。
综上,我的这个问题可以这个样子解决。
出问题之前的代码:
void *thread_rounter(void *)//线程执行函数
{
//直接访问类的成员
}
exec_task函数中调用:
pthread_create(&tid,null,thread_rounter,null);//启动线程执行例程
修复这个问题的代码:
static void *thread_rounter(void *tmp)/线程执行函数
{
threadpool *p=(threadpool *)tmp;
//通过p指针间接访问类的非静态成员
}
exec_task函数中调用:
pthread_create(&tid,null,thread_rounter,(void *)this);//启动线程执行例程
-----------------------------------------------------------------
方案二:
将线程启动函数声明为模板函数。
templatevoid* _thread_t(void* param)//线程启动函数,声明为模板函数 { type* this = (type*)param; this->_runthread(); return null; } class myclass { public: myclass(); void _runthread(); private: pthread_t tid; }; void myclass::_runthread() { this->dosomething(); } myclass::myclass() { pthread_create(&tid, null, _thread_t , this); } //函数模版不单可以替换类型本身,还能替换类型的成员函数。 //注意: 1、名称只能是_runthread,不能在指定模版参数的时候修改; // 2、_runthread只能是public的,除非把_thread_t定义到myclass的内部。
采取这个方案放入我的项目中:
出问题之前的代码:
void *thread_rounter(void *)//线程执行函数
{
//直接访问类的成员
}
exec_task函数中调用:
pthread_create(&tid,null,thread_rounter,null);//启动线程执行例程
修复这个问题的代码:
添加public成员函数:
void run()
{
//该函数替换上述thread_rounter的执行代码
}
thread_rounter修改为全局模板函数:
template
void * thread_rounter(void * param)
{
type *p=(type*)param;
p->run();
return null;
}
exec_task函数中调用:
pthread_create(&tid,null,thread_rounter
总结:
解决这个问题的关键在于想方设法使启动函数指针满足void*(*)(void *)类型。
将启动函数改写成static成员函数适用于可以修改类的源代码的情况。
而将启动函数写成模板函数还可以适用于没有类的源代码的情况,自己写一个类,公共继承自原类,添加启动函数为模板函数即可。