http://blog.csdn.net/luo6620378xu/article/details/8521940
近日需要將線程池封裝成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);//啟動線程執行例程
----------------------------------------------------------------------------------------------------------------------
在網上搜索一下還有其他的解決方案,摘錄如下,為了以示尊重標明文章來源,感謝原文作者。
方案二:
將線程啟動函數聲明為模板函數。
摘錄自:http://hi.baidu.com/angelevil2006/item/e1806ec30574ff11515058d1
- template <typename TYPE, void (TYPE::*_RunThread)() >
- void* _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<MyClass, &MyClass::_RunThread>, 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 <typename TYPE, void (TYPE::*Run)() >
void * thread_rounter(void * param)
{
TYPE *p=(TYPE*)param;
p->Run();
return NULL;
}
exec_task函數中調用:
pthread_create(&tid,NULL,thread_rounter<Threadpool,&Threadpool::Run>,(void *)this);
總結:
解決這個問題的關鍵在於想方設法使啟動函數指針滿足void*(*)(void *)類型。
將啟動函數改寫成static成員函數適用於可以修改類的源代碼的情況。
而將啟動函數寫成模板函數還可以適用於沒有類的源代碼的情況,自己寫一個類,公共繼承自原類,添加啟動函數為模板函數即可。