首先咱們須要搞清楚一個問題,爲何咱們要用Thunk技術?Thunk技術能夠解決神馬難題?html
在探尋上面的問題以前先講述一下線程從面向過程到面相對象編程所面臨的問題和解決的方法,由於Thunk也是爲了解決這些問題而產生的c++
咱們知道用Window的API來開發程序的話其實是用的C語言的面向過程的方式來開發的。編程
而在咱們使用C++開發程序的時候一般都是用的OOP(面向對象編程)的方式來編寫的。函數
例如在C語言裏面建立線程時是直接用_beginthread()一條函數就 能夠的了,而在c++裏面咱們一般想要封裝成一個線程類。ui
來看看線程是怎麼轉變的?先看下_beginthread()的聲名this
uintptr_t _beginthread( void( __cdecl *start_address )( void * ), unsigned stack_size, void *arglist);
_beginthread()的第一個參數說明了咱們要建立線程就須要定義一個像下面這樣格式的函數線程
void ThreadFunc(void* pVoid);
在C的面相過程的編程方式中實際上這個函數是一個裸露在外的全局函數,若是咱們要將它封裝到類裏面怎麼作呢?咱們最直接的想法是這樣作指針
class MyClass { public: void StartThread() { _beginthread(ThreadFunc, NULL, NULL); } ... void ThreadFunc(void* pVoid); ... }
可是實際上這樣會編譯錯誤的,由於ThreadFunc做爲成員函數會被編譯器編譯爲這樣的格式,致使在編譯的時候參數不一致code
void MyClass::ThreadFunc(this, void* pVoid)
成員函數會被加上this指針,若是不知道爲何就百度一下編譯器編譯成員函數的方法吧。。。htm
那麼是否是ThreadFunc沒辦法放在類裏面了呢?有沒有解決辦法呢?有的,只要把ThreadFunc聲名爲類的靜態成員函數就能夠了,由於被聲名爲static的函數是不會被在參數列表裏面加上this指針的。因而修改以下
class MyClass { public: void StartThread() { _beginthread(ThreadFunc, NULL, NULL); } ... static void ThreadFunc(void* pVoid); ... }
可是這樣的話問題又來了,咱們知道靜態成員函數其實是不屬於類的任何對象的,也就是靜態函數沒法訪問類對象的成員變量,由於它沒有this指針。
這是個很是糟糕的狀況啊,由於咱們的線程一般都要訪問類對象的成員變量的(總要存取某些值之類的吧),那麼咱們是否是能夠嘗試把this指針傳遞給靜態函數ThreadFunc呢?這樣咱們就能用這個this指針作普通成員函數作的事情了。
咱們注意到ThreadFunc(void* pVoid)是有個void類型的指針的參數傳入的,從字面意思是能夠傳入任意的指針的。那麼咱們就從這個入手,咱們把this指針用這個pVoid參數傳入進去。再在ThreadFunc內部轉換一下指針類型就大功告成了。
再往上看一下_beginthread()的聲名,發現最後一個參數實際上就是會傳遞給ThreadFunc的void參數的。咱們這樣作就能夠了
class MyClass { public: void StartThread() { _beginthread(ThreadFunc, NULL, this); } ... void ThreadFunc(void* pVoid); ... }
線程從面向過程到面向對象的轉變有些曲折,可是總歸是順利的利用pVoid這個預留的參數解決了
後續繼續討論Thunk是如何實現的