c++学习笔记之基础---类内声明线程函数的调用
??近日需要將線程池封裝成C++類(lèi),類(lèi)名為T(mén)hreadpool。在類(lèi)的成員函數(shù)exec_task中調(diào)用pthread_create去啟動(dòng)線程執(zhí)行例程thread_rounter。編譯之后報(bào)錯(cuò)如下:
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*)’
? ? 出現(xiàn)類(lèi)型不匹配的問(wèn)題。因?yàn)閜thread_create需要的參數(shù)類(lèi)型為void*?(*)(void*),而thread_rounter作為類(lèi)的成員函數(shù)時(shí)其類(lèi)型是void*?(Threadpool::)(void*)的成員函數(shù)指針。我們知道類(lèi)的成員函數(shù)在經(jīng)過(guò)編譯器處理之后,會(huì)變成帶有this指針參數(shù)的全局函數(shù),所以類(lèi)型注定是不會(huì)匹配的。但是如果將thread_rounter聲明為static類(lèi)型,那么編譯器會(huì)將static形式的函數(shù),轉(zhuǎn)換成不帶this指針的全局函數(shù),所以其類(lèi)型可以與pthread_create需要的參數(shù)類(lèi)型相匹配。但是類(lèi)的靜態(tài)成員函數(shù)無(wú)法訪問(wèn)類(lèi)的非靜態(tài)成員,不過(guò)這可以通過(guò)傳遞this指針解決這個(gè)問(wèn)題。
綜上,我的這個(gè)問(wèn)題可以這個(gè)樣子解決。
出問(wèn)題之前的代碼:
void?*thread_rounter(void?*)//線程執(zhí)行函數(shù)
{
???//直接訪問(wèn)類(lèi)的成員
}
?
exec_task函數(shù)中調(diào)用:
pthread_create(&tid,NULL,thread_rounter,NULL);//啟動(dòng)線程執(zhí)行例程
?
修復(fù)這個(gè)問(wèn)題的代碼:
static?void?*thread_rounter(void?*tmp)/線程執(zhí)行函數(shù)
{
??Threadpool?*p=(Threadpool?*)tmp;
????//通過(guò)p指針間接訪問(wèn)類(lèi)的非靜態(tài)成員
?
}
?
exec_task函數(shù)中調(diào)用:
pthread_create(&tid,NULL,thread_rounter,(void?*)this);//啟動(dòng)線程執(zhí)行例程
----------------------------------------------------------------------------------------------------------------------
?
在網(wǎng)上搜索一下還有其他的解決方案,摘錄如下,為了以示尊重標(biāo)明文章來(lái)源,感謝原文作者。
?
方案二:
將線程啟動(dòng)函數(shù)聲明為模板函數(shù)。
摘錄自:http://hi.baidu.com/angelevil2006/item/e1806ec30574ff11515058d1
[cpp]?view plaincopy?
采取這個(gè)方案放入我的項(xiàng)目中:
?
出問(wèn)題之前的代碼:
void?*thread_rounter(void?*)//線程執(zhí)行函數(shù)
{
???//直接訪問(wèn)類(lèi)的成員
}
?
exec_task函數(shù)中調(diào)用:
pthread_create(&tid,NULL,thread_rounter,NULL);//啟動(dòng)線程執(zhí)行例程
?
修復(fù)這個(gè)問(wèn)題的代碼:
添加public成員函數(shù):
?
void?Run()
{
??//該函數(shù)替換上述thread_rounter的執(zhí)行代碼
}
?
thread_rounter修改為全局模板函數(shù):
?
template?<typename?TYPE,?void?(TYPE::*Run)()?>
void?*?thread_rounter(void?*?param)
{
????TYPE?*p=(TYPE*)param;
????p->Run();
????return?NULL;
}
?
exec_task函數(shù)中調(diào)用:
pthread_create(&tid,NULL,thread_rounter<Threadpool,&Threadpool::Run>,(void?*)this);
?
總結(jié):
解決這個(gè)問(wèn)題的關(guān)鍵在于想方設(shè)法使啟動(dòng)函數(shù)指針滿(mǎn)足void*(*)(void?*)類(lèi)型。
?
將啟動(dòng)函數(shù)改寫(xiě)成static成員函數(shù)適用于可以修改類(lèi)的源代碼的情況。
?
而將啟動(dòng)函數(shù)寫(xiě)成模板函數(shù)還可以適用于沒(méi)有類(lèi)的源代碼的情況,自己寫(xiě)一個(gè)類(lèi),公共繼承自原類(lèi),添加啟動(dòng)函數(shù)為模板函數(shù)即可。
花了三個(gè)工作日把原來(lái)寫(xiě)的一段通信守護(hù)進(jìn)程代碼從過(guò)程方法改到了 template class,對(duì)于 template 的使用和類(lèi)的派生明白了不少道理。還有個(gè)很受啟發(fā)的一點(diǎn),就是 C++ 中如何使用類(lèi)的成員函數(shù)作為創(chuàng)建線程的開(kāi)始函數(shù)。
pthread_create 是 POSIX 標(biāo)準(zhǔn)下創(chuàng)建線程的函數(shù),函數(shù)原型是:
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void*(*start_routine)(void *), void *arg);
在 C 中,這個(gè)函數(shù)使用很簡(jiǎn)單,只要定義一個(gè)參數(shù)和返回值均為 void * 類(lèi)型的函數(shù),使用函數(shù)名字作為參數(shù)即可。就算不完全符合,可以使用 (void *(*)(void *)) 將其強(qiáng)制轉(zhuǎn)換為符合類(lèi)型檢查規(guī)格的函數(shù)指針。但是,類(lèi)的非靜態(tài)成員函數(shù)隱含 this 指針作為第一個(gè)參數(shù),所以參數(shù)完全不可能轉(zhuǎn)化為 void * 類(lèi)型,而 C++ 的類(lèi)型檢查要比 C 嚴(yán)格許多。由于我原來(lái)寫(xiě)的代碼是 C 風(fēng)格的,自然不會(huì)出現(xiàn)類(lèi)型不符的問(wèn)題,現(xiàn)在將線程開(kāi)始函數(shù)封裝到一個(gè)模板類(lèi)中,再創(chuàng)建線程的時(shí)候就不能滿(mǎn)足需要了。
在試了幾種轉(zhuǎn)換無(wú)效之后,從網(wǎng)上搜到一種方法:定義線程開(kāi)始函數(shù)為類(lèi)的靜態(tài)成員函數(shù)(static member function),這樣就不隱含 this 指針了,然后將 this 指針從 pthread_create 最后一個(gè)參數(shù)傳給開(kāi)始函數(shù),在函數(shù)中將 void * 類(lèi)型的 this 指針強(qiáng)制轉(zhuǎn)換為類(lèi)指針。看來(lái)靜態(tài)成員函數(shù)還是有些妙用的。
===================我叫分割線===================
帶著我媽和我妹在北京城里轉(zhuǎn)悠了幾天,累得不行。主要原因在我,沒(méi)有考慮到身體因素,連著玩消耗太大,再加上自己也沒(méi)車(chē)沒(méi)房,倒公交車(chē)和住賓館也要走很遠(yuǎn),費(fèi)時(shí)間又費(fèi)勁。我都快受不了了,別說(shuō)我媽了。以后再出去旅游,堅(jiān)決不會(huì)再連著轉(zhuǎn)三天以上,要么緊緊張張地玩兩天,要么就花時(shí)間長(zhǎng)點(diǎn)兒,走走歇歇。唉,誰(shuí)讓咱是窮人呢,又有錢(qián)又有閑的日子還沒(méi)過(guò)上呢!
今天看了下積壓很久的博客訂閱,同學(xué)里開(kāi)始寫(xiě)和繼續(xù)寫(xiě)的人越來(lái)越多了。覺(jué)得有些文章比較陰沉低迷,因?yàn)樽约簭拇笕_(kāi)始心情就老是跌宕起伏,反而在面對(duì)這許多次的分別聚首時(shí)坦然一些。要不是周熹在散伙飯時(shí)候?qū)iT(mén)招我,也不會(huì)哭得那么厲害。散了散了散了吧,沒(méi)有離別,怎么會(huì)有重逢呢?
還是在 Yourui 的博客上看到小恪去新疆的消息,要是當(dāng)面看到他,肯定會(huì)玩笑說(shuō)發(fā)配三千里伊犁充軍去了。這在邊關(guān)待了兩年之后,再回來(lái)學(xué)積分拓?fù)渲?lèi)的數(shù)學(xué)還能看得下去嗎?都說(shuō)是命運(yùn)無(wú)常,旅途坎坷卻能看更美風(fēng)景,只是不知道那關(guān)外還是不是大漠孤煙長(zhǎng)河落日的大西北?
剛才去吃飯,走在晚間暖暖的懶洋洋的空氣中,忽然有點(diǎn)兒秋天的感覺(jué)。想起 7 年前爸爸送我到商丘一高上學(xué)的情景,日子可真快啊!老了,老了!
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
總結(jié)
以上是生活随笔為你收集整理的c++学习笔记之基础---类内声明线程函数的调用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: HDU-4902-Nice boat
- 下一篇: 一、spring mvc简介