c++学习笔记之基础---类内声明线程函数的调用
??近日需要將線程池封裝成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
[cpp]?view plaincopy?
采取這個方案放入我的項目中:
?
出問題之前的代碼:
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成員函數適用于可以修改類的源代碼的情況。
?
而將啟動函數寫成模板函數還可以適用于沒有類的源代碼的情況,自己寫一個類,公共繼承自原類,添加啟動函數為模板函數即可。
花了三個工作日把原來寫的一段通信守護進程代碼從過程方法改到了 template class,對于 template 的使用和類的派生明白了不少道理。還有個很受啟發的一點,就是 C++ 中如何使用類的成員函數作為創建線程的開始函數。
pthread_create 是 POSIX 標準下創建線程的函數,函數原型是:
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void*(*start_routine)(void *), void *arg);
在 C 中,這個函數使用很簡單,只要定義一個參數和返回值均為 void * 類型的函數,使用函數名字作為參數即可。就算不完全符合,可以使用 (void *(*)(void *)) 將其強制轉換為符合類型檢查規格的函數指針。但是,類的非靜態成員函數隱含 this 指針作為第一個參數,所以參數完全不可能轉化為 void * 類型,而 C++ 的類型檢查要比 C 嚴格許多。由于我原來寫的代碼是 C 風格的,自然不會出現類型不符的問題,現在將線程開始函數封裝到一個模板類中,再創建線程的時候就不能滿足需要了。
在試了幾種轉換無效之后,從網上搜到一種方法:定義線程開始函數為類的靜態成員函數(static member function),這樣就不隱含 this 指針了,然后將 this 指針從 pthread_create 最后一個參數傳給開始函數,在函數中將 void * 類型的 this 指針強制轉換為類指針??磥盱o態成員函數還是有些妙用的。
===================我叫分割線===================
帶著我媽和我妹在北京城里轉悠了幾天,累得不行。主要原因在我,沒有考慮到身體因素,連著玩消耗太大,再加上自己也沒車沒房,倒公交車和住賓館也要走很遠,費時間又費勁。我都快受不了了,別說我媽了。以后再出去旅游,堅決不會再連著轉三天以上,要么緊緊張張地玩兩天,要么就花時間長點兒,走走歇歇。唉,誰讓咱是窮人呢,又有錢又有閑的日子還沒過上呢!
今天看了下積壓很久的博客訂閱,同學里開始寫和繼續寫的人越來越多了。覺得有些文章比較陰沉低迷,因為自己從大三開始心情就老是跌宕起伏,反而在面對這許多次的分別聚首時坦然一些。要不是周熹在散伙飯時候專門招我,也不會哭得那么厲害。散了散了散了吧,沒有離別,怎么會有重逢呢?
還是在 Yourui 的博客上看到小恪去新疆的消息,要是當面看到他,肯定會玩笑說發配三千里伊犁充軍去了。這在邊關待了兩年之后,再回來學積分拓撲之類的數學還能看得下去嗎?都說是命運無常,旅途坎坷卻能看更美風景,只是不知道那關外還是不是大漠孤煙長河落日的大西北?
剛才去吃飯,走在晚間暖暖的懶洋洋的空氣中,忽然有點兒秋天的感覺。想起 7 年前爸爸送我到商丘一高上學的情景,日子可真快啊!老了,老了!
http://bbs.chinaunix.net/thread-724023-1-1.html http://blog.solrex.org/articles/class-member-function-as-pthread_create-argument.htmlhttp://blog.csdn.net/luo6620378xu/article/details/8521940
總結
以上是生活随笔為你收集整理的c++学习笔记之基础---类内声明线程函数的调用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU-4902-Nice boat
- 下一篇: BZOJ3476 : [Usaco201