Created
August 28, 2011 19:17
-
-
Save alexandruc/1177079 to your computer and use it in GitHub Desktop.
Dispatcher class: asynchronousely dispathces messages
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <windows.h> | |
#include <queue> | |
/** | |
* Default deallocation function (no deallocation) | |
*/ | |
typedef void (*noDeleteFunction)(...); | |
/** \p Dispatcher class: asynchronousely dispathces messages | |
* \t Template instantiation: | |
* @param ClassPtr Pointer to class from which the fPtr method will be called | |
* @param fPtr Pointer to class method which will be used for dispatching messages | |
* @param MsgType Type of the message to be dispatched | |
* @param pfMsgDealloc Pointer to function which will be called to deallocate messages (in case of usage of complex types) | |
*/ | |
template <class ClassPtr, class fPtr, class MsgType, typename pfMsgDealloc=noDeleteFunction> | |
class Dispatcher | |
{ | |
public: | |
/** | |
* Default constructor | |
*/ | |
Dispatcher(void): m_csLock(), | |
m_messageQueue(), | |
m_pf(0), | |
m_pClass(0), | |
m_thHandle(0), | |
m_thSyncEvent(0), | |
m_bKillTh(0), | |
m_pfDelete(0), | |
m_bInitialized(false) | |
{ | |
InitializeCriticalSection(&m_csLock); | |
}; | |
/** | |
* Default destructor | |
*/ | |
~Dispatcher(void) | |
{ | |
DeleteCriticalSection(&m_csLock); | |
}; | |
/** | |
* Method used to insert messages in the dispatcher queue | |
* @param message Message to be dispatched | |
*/ | |
void dispatch(MsgType message) | |
{ | |
EnterCriticalSection(&m_csLock); | |
//add message for decoupling | |
m_messageQueue.push(message); | |
SetEvent(m_thSyncEvent); //let the thread process the event | |
LeaveCriticalSection(&m_csLock); | |
}; | |
/** | |
* Method used to initialize the dispatcher | |
* @param pClass Pointer to object from which the class method will be called | |
* @param pf Pointer to member function which will be called to process the message | |
* @param pfMsgDealloc Pointer to function used to deallocate the message | |
* @return true for successful initialization, false otherwise | |
*/ | |
bool initializeDispatcher(ClassPtr pClass, fPtr pf, pfMsgDealloc pfDelete=0) | |
{ | |
EnterCriticalSection(&m_csLock); | |
bool retVal = true; | |
DWORD dwThreadId = 0; | |
if(!m_bInitialized) | |
{ | |
m_pClass = pClass; | |
m_pf = pf; | |
m_pfDelete = pfDelete; | |
m_thSyncEvent = CreateEvent(NULL, TRUE /* man reset */, FALSE /* non-signaled first */, L"NotificationThreadEvent"); | |
if(m_thSyncEvent == NULL) | |
{ | |
printf("Dispatcher::initializeDispatcher: failed to create dispatcher event \n"); | |
retVal = false; | |
} | |
if(retVal) | |
{ | |
m_thHandle = CreateThread(NULL, NULL, notificationThProcWrapper, this, NULL, &dwThreadId); | |
if(m_thHandle == NULL) | |
{ | |
printf("Dispatcher::initializeDispatcher: failed to create dispatcher thread \n"); | |
retVal = false; | |
} | |
} | |
if(retVal) | |
{ | |
m_bInitialized = true; | |
} | |
} | |
LeaveCriticalSection(&m_csLock); | |
return retVal; | |
}; | |
/** | |
* Unitializes dispatcher - deallocates resources | |
*/ | |
void uninitializeDispatcher() | |
{ | |
EnterCriticalSection(&m_csLock); | |
//uninitialize thread | |
m_bKillTh = true; | |
SetEvent(m_thSyncEvent); | |
WaitForSingleObject(m_thHandle, INFINITE); | |
//close handles | |
CloseHandle(m_thHandle); | |
CloseHandle(m_thSyncEvent); | |
//clear the queue (objects should have a proper destructor implemented) | |
while(!m_messageQueue.empty()) | |
{ | |
MsgType message = m_messageQueue.front(); | |
m_messageQueue.pop(); | |
deallocateMessage(message); | |
} | |
m_bInitialized = false; | |
LeaveCriticalSection(&m_csLock); | |
}; | |
/** | |
* Thread procedure | |
*/ | |
void notificationThProc() | |
{ | |
while(true) | |
{ | |
DWORD dwWaitVal = 0; | |
dwWaitVal = WaitForSingleObject(m_thSyncEvent, INFINITE); | |
if(m_bKillTh) | |
{ | |
break; | |
} | |
switch(dwWaitVal) | |
{ | |
case WAIT_TIMEOUT: | |
{ | |
} | |
case WAIT_OBJECT_0: | |
{ | |
EnterCriticalSection(&m_csLock); | |
if(m_messageQueue.empty()) | |
{ | |
ResetEvent(m_thSyncEvent); //no more data -> stop thread | |
} | |
else | |
{ | |
MsgType& message = m_messageQueue.front(); | |
if(m_pf != 0) | |
{ | |
//process the message | |
(m_pClass->*m_pf)(*message); | |
//remove message from queue | |
m_messageQueue.pop(); | |
//deallocate the message | |
deallocateMessage(message); | |
} | |
} | |
LeaveCriticalSection(&m_csLock); | |
} | |
break; | |
default: | |
{ | |
} | |
break; | |
} | |
} | |
}; | |
private: | |
/** | |
* Deallocation method - will call pointer to deallocation function | |
* @param message Message object to be deallocated | |
*/ | |
void deallocateMessage(MsgType& message) | |
{ | |
if(m_pfDelete != 0) | |
{ | |
m_pfDelete(message); | |
} | |
}; | |
/** | |
* Wrapper of the notification thread | |
* @param param Parameter sent to thread method | |
*/ | |
static DWORD WINAPI notificationThProcWrapper(LPVOID param) | |
{ | |
Dispatcher<ClassPtr, fPtr, MsgType>* obj = reinterpret_cast< Dispatcher<ClassPtr, fPtr, MsgType>* >(param); | |
obj->notificationThProc(); | |
return 0; | |
}; | |
private: | |
CRITICAL_SECTION m_csLock; /**< synchronization lock */ | |
std::queue<MsgType> m_messageQueue; /**< queue to hold the notifications */ | |
fPtr m_pf; /**< pointer to function */ | |
ClassPtr m_pClass; /**< pointer to the class object whose function will be called */ | |
HANDLE m_thHandle; /**< Handle of the notification thread */ | |
HANDLE m_thSyncEvent; /**< Handle of the event which will synchronize the thread */ | |
bool m_bKillTh; /**< Guard used to safely close the dispatcher thread */ | |
pfMsgDealloc m_pfDelete; /**< function used to deallocate messages (in case it's needed - complex types) */ | |
bool m_bInitialized; /**< Guard to check if this instance of the dispatcher is initialized */ | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment