WTL|Thunk技术的一些理解(一)

首先我们需要搞清楚一个问题,为什么我们要用Thunk技术?Thunk技术可以解决神马难题? 在探寻上面的问题之前先讲述一下线程从面向过程到面相对象编程所面临的问题和解决的方法,因为Thunk也是为了解决这些问题而产生的
我们知道用Window的API来开发程序的话实际上是用的C语言的面向过程的方式来开发的。
而在我们使用C++开发程序的时候通常都是用的OOP(面向对象编程)的方式来编写的。
例如在C语言里面创建线程时是直接用_beginthread()一条函数就 可以的了,而在c++里面我们通常想要封装成一个线程类。
来看看线程是怎么转变的?先看下_beginthread()的声名

uintptr_t _beginthread( // NATIVE CODE 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作为成员函数会被编译器编译为这样的格式,导致在编译的时候参数不一致
void MyClass::ThreadFunc(this, void* pVoid)

成员函数会被加上this指针,如果不知道为什么就百度一下编译器编译成员函数的方法吧。。。
那么是不是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); ... }

【WTL|Thunk技术的一些理解(一)】 线程从面向过程到面向对象的转变有些曲折,但是总归是顺利的利用pVoid这个预留的参数解决了

    推荐阅读