今天写了一个类,类中用到了创建线程函数:_beginthreadex() (windows下的创建线程函数,这其实是一个C标准的线程函数,但跟windows联系紧密,只要是为解决Create_Thread()函数创建的线程如果调用了C函数库,就会发生内存泄露,所以这是个安全的函数,建议用这个。) 以下是一个成员函数的某段代码:
HANDLE hth;
unsigned uiThread1ID;
hth = (HANDLE)_beginthreadex( NULL, // security
0, // stack size
NetRawThreadProc,
this, // arg list
0, // so we can later call ResumeThread()
&uiThread1ID );
CloseHandle(hth);
功能就是创建一个线程,然后线程去执行NetRawThreadProc(),这个NetRawThreadProc 也是一个类成员函数,它的原型为:
void* NetWorkThread::NetRawThreadProc (void* pParam)
{
//blablabla~~~
}
然后编译一下,傻眼了,说该成员函数与回调类型不匹配噢,MLGB!
我从头到尾都是参照标准的方法,来调用回调函数啊(因为还不知道this指针这个鬼~)
所以我的解决思路是:
1. 回调类型不匹配,我就先check 我的NetRawThreadProc() 的返回值类型、参数类型,发现没有错;
2.是否_beginthreadex()的第三个参数给错了,然后查到这第三个参数,有两种使用方式,一种是在调用的函数名前面加 & ,一种是不加:
函数名,本来就是函数地址,这时候再加个 & 也是一样,地址不会发生改变,所以还是能够调用;
3.可能是NetWorkThread::有问题:
try了一下,把NetWrokThread:: 去掉后再来调用,就一切正常。
找到问题了,成员函数作为回调函数,会出问题。
解决方法一:
用普通函数来做中间层:
void* func(void*)
普通函数为上述格式,然后利用回调函数的特性,传递 this 指针到第四个参数,然后func()就可以使用this指针来调用类成员函数了,相当折中。
但我不喜欢这个方式,因为这样封装性就破坏了。
这个时候有第二种解决方法:使用static 成员函数作为回调函数,然后在static中调用成员函数;
void* NetWorkThread::NetRawThreadProc (void* pParam)
{
NetThreadProc();
}
此时编译报错,提示NetThreadProc也需要是静态成员;我在这里调用成员函数,而不是直接用static成员函数来进行操作,是因为static要操作的类成员变量必须是static的,这样我就需要把成员变量该为static了。所以必须要用某种方法来调用成员函数。
我们可以利用回调函数传递this指针,迂回解决这个问题:
void* NetWorkThread::NetRawThreadProc (void* pParam)
{
NetWorkThread *netObject = (NetWorkThread*)pParam;
netObject->NetThreadProc();
}
这样,类成员函数就能正确调用了,整体格式为:
HANDLE hth;
unsigned uiThread1ID;
hth = (HANDLE)_beginthreadex( NULL, // security
0, // stack size
NetRawThreadProc,
this, // arg list
0, // so we can later call ResumeThread()
&uiThread1ID );
CloseHandle(hth);
void* NetWorkThread::NetRawThreadProc (void* pParam)
{
NetWorkThread *netObject = (NetWorkThread*)pParam;
netObject->NetThreadProc();
}
void NetWorkThread::NetThreadProc(){//blablalbla}