有时候会碰到一些的C++程序员定义的异步函数(通过Callback通知)没有UserData参数,这样会给OO设计带来很大的麻烦。举个例子(只是例子,不讨论有没有必要作成异步函数):
typedef void (*PFCALLBACK)();
DWORD WorkingFunc(LPVOID* param)
{
// Do something...
PFCALLBACK pFun = (PFCALLBACK)param;
pFun ();
return 0;
}
void Asynchronous(PFCALLBACK pCallbak)
{
HANDLE hThrd = CreateThread(NULL, 0, WorkingFunc, pCallbak, 0, NULL);
CloseHandle(hThrd );
}
如果要调用Asynchronous这个函数,通常可以这么做:
class myClass
{
public:
static void myCallback();
void myFunction();
private:
static HANDLE m_hEvent;
};
HANDLE myClass::m_hEvent= NULL:
void myClass::myCallback()
{
SetEvent(m_hEvent);
}
void myClass::myFunction()
{
m_hEvent= CreateEvent(NULL, FALSE, FALSE, NULL);
Asynchronous(myCallback);
// Do some thing
WaitForSingleObject(m_hEvent, INFINITE);
CloseHandle(m_hEvent);
m_hEvent = NULL;
}
由于m_hEvent是静态成员变量,所有的类的对象都共用一个m_hEvent,所以当这些对象在不同线程中被调用时就可能造成错误!
所以,我们在设计使用Callback的异步函数时,应该预留UserData参数,这样,代码变成以下方式:
typedef void (*PFCALLBACK)(void* UserData);
struct ThreadParam
{
PFCALLBACK pCallback;
void* UserData;
};
DWORD WorkingFunc(LPVOID param)
{
// Do something...
ThreadParam* pParam = (ThreadParam*)param;
pParam->pCallback(pParam->UserData);
delete pParam;
return 0;
}
void Asynchronous(PFCALLBACK pCallbak, void* UserData)
{
ThreadParam *pParam = new ThreadParam;
pParam ->pCallback = pCallbak;
pParam ->UserData = UserData;
HANDLE hThrd = CreateThread(NULL, 0, WorkingFunc, pParam , 0, NULL);
CloseHandle(hThrd);
}
而myClass可以实现成:
class myClass
{
public:
static void myCallback(void* UserData);
void myFunction();
};
void myClass::myCallback(void* UserData)
{
HANDLE hHandle = (HANDLE)UserData
SetEvent(hHandle);
}
void myClass::myFunction()
{
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
Asynchronous(myCallback, hEvent);
// Do some thing
WaitForSingleObject(hEvent, INFINITE);
CloseHandle(hEvent);
}
由于去掉了静态成员变量,所以在多线程的环境下也能保证正确工作。
大家可以去参考微软的Callback的设计,几乎都留了UserData或者类似的参数。